Linux QOS:Тестирование различных вариантов управленя траффиком: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
Строка 331: Строка 331:
 
<BR>
 
<BR>
 
Насколько я могу судить алгоритм достаточно точный - снимаемые с ноды значения соответвуют выставляемым на роутере.
 
Насколько я могу судить алгоритм достаточно точный - снимаемые с ноды значения соответвуют выставляемым на роутере.
  +
  +
===Классовые дисциплины===
  +
Для простых случаев можно использовать и классовые дисциплины - при этом конструкции будут достаточно простые и понятные.
  +
====HTB====
  +
====HFSC====
  +
http://ace-host.stuart.id.au/russell/files/tc/doc/sch_hfsc.txt
   
 
==Источники==
 
==Источники==

Версия 10:28, 19 июня 2015

Linux Shaper

Эта тема всегда вызывала у меня некоторые затруднения и потому я решил систематизировать свои знания.

Описание лаборатории

Для тестирования я использую лабу из 3 виртуальных машин, виртуалбокс. Базовая ОС - Мак Ос

|-------|               |--------|               |-------|
|node-1 |-eth0-----eth1-|router0 |-eth2-----eth0-|node-2 |
|-------|               |--------|               |-------|
                            |
                           eth0
                            |
                           HOST

node-1

  • 192.168.1.2
  • Алиасами добавлены адреса 192.168.1.3-100

node-1

  • 192.168.2.2
  • Алиасами добавлены адреса 192.168.2.3-100

Router0

  • eth1: 192.168.1.1
  • eth2: 192.168.2.1

eth0 - служит для доступа к лабе и никак в тестах не участвует.
Все политики клсассы и прочее - только на транзитных интерфейсах eth1 и eth2


Базовое тестирование-ограничение скорости

Так как планируется большое число тестов и большое число данных, то первым делом нужно подготовить автоматизацию. Для генерации трафика я буду использовать iperf с переменным числом потоков, для сбора статистики - скрипт на питоне. Для визуализации - GnuPlot

Как тестируем

Тест проходит следующим образом:

  • на node-1 запущены множество экземпляров iperf в режиме сервера
BASE_PORT=5000

for I in `seq 2 100`
do
    let PORT=BASE_PORT+I
    echo ${PORT}
    iperf -s -l 32k -w 512k -u -p ${PORT} -D
    iperf -s -l 32k -w 512k    -p ${PORT} -D
done
  • на node-2 запускается iperf в 30 потоков, каждый - на другой порт и на другой IP, для того что бы в дальнейших тестах проверять классы трафика и

для более равномерного распределения. sleep 30 - нужен для того что бы успеть запустить счетчики на ноде 1
В случае когда условия тестирования отличаются - я буду указывать отдельно

#!/bin/bash

sleep 30

BASE_PORT=5000
for I in `seq 2 ${1}`
do
.
 IP=192.168.1.${I}
 let PORT=BASE_PORT+I
 #echo iperf -c ${IP}  -b 100000M  -i 1  -l 60K -t 120  -p ${PORT} -D
 iperf -c ${IP}  -b 100000M  -i 1  -l 60K -t 120  -p ${PORT} -D
 iperf -c ${IP}  -b 100000M  -i 1  -l 60K -t 120  -p ${PORT} -u -D
done
  • В процессе работы собираем траффик наколенном скриптом на питоне и складываем в лог, потом рисуем график используя GnuPLOT
import time
import datetime as dt
import sys

stop_time=time.time()+300
iface='eth0'
sleep_time=0.5

tx_data_file = open('/sys/class/net/'+iface+'/statistics/tx_bytes', 'r')
rx_data_file = open('/sys/class/net/'+iface+'/statistics/rx_bytes', 'r')
res_file = open(str(sys.argv[1]),'w')

for l in rx_data_file:
  in_bytes_prev=int(l)

for l in tx_data_file:
  out_bytes_prev=int(l)

while True:
  try:
    rx_data_file.seek(0)
    tx_data_file.seek(0)

    for l in rx_data_file:
      in_bytes=int(l)
    for l in tx_data_file:
      out_bytes=int(l)


    in_bytes_diff=in_bytes-in_bytes_prev
    out_bytes_diff=out_bytes-out_bytes_prev

    in_bytes_prev=in_bytes
    out_bytes_prev=out_bytes
    time.sleep(sleep_time)

    res_file.write(str(time.time())+" "+str((in_bytes_diff)*8/sleep_time)+" "+str((out_bytes_diff)*8/sleep_time)+"\n")
    print str(time.time())+" "+str(in_bytes_prev)+" "+str(in_bytes)+" "+str((in_bytes_diff)*8)+" "+str(out_bytes_prev)+" "+str(out_bytes)+" "+str(out_bytes_diff)+" IN="+str((in_bytes_diff)*8/1024/1024/sleep_time)+" OUT="+str((out_bytes_diff)*8/1024/1024/sleep_time)

    if time.time()>stop_time:
      break
  except:
      break
res_file.close()

Скрипт для GnuPlot - заготовка из кототорой на лету формируем awk то что надо - подставляя входной файл, имя графика и т.д.

#!/usr/bin/gnuplot -persist

set terminal png  size 1400,600
# Размер и формат графика.

set output "/root/no_shaper.png"

set title "no_shaper"
# Заголовок

set nokey
# не знаю. Уточнить.
set key top left
# Расположение подписи
set key box
# Оформление (в рамке) подписи к графикам


set xlabel "Date"
# Метка по оси Х

set xdata time
# Описать что по оси Х время (формат ниже)
set timefmt "%s"
# Формат даты соответвует формату gnu date
# В моем случае был удобен такой формат.

set ylabel "Traffic"
#set format y '%.0s%cB'
set format y '%s'

plot \
"/root/no_shaper.log"  using 1:2 with lines  title "IN, bit/s"  smooth bezier, \
"/root/no_shaper.log"  using 1:2 with lines  title "IN, bit/s"  , \
"/root/no_shaper.log"  using 1:3 with lines  title "OUT, bit/s" smooth bezier, \
"/root/no_shaper.log"  using 1:3 with lines  title "OUT, bit/s"
[root@node-1 ~]# cat plot.sh
#!/usr/bin/gnuplot -persist

set terminal png  size 1400,600
# Размер и формат графика.

set output "___OUTPUT_FILE___"

set title "___TITLE_OF_PLOT___"
# Заголовок

set nokey
# не знаю. Уточнить.
set key top left
# Расположение подписи
set key box
# Оформление (в рамке) подписи к графикам


set xlabel "Date"
# Метка по оси Х

set xdata time
# Описать что по оси Х время (формат ниже)
set timefmt "%s"
# Формат даты соответвует формату gnu date
# В моем случае был удобен такой формат.

set ylabel "Traffic"
#set format y '%.0s%cB'
set format y '%s'

plot \
"___INPUT_FILE___"  using 1:2 with lines  title "IN, bit/s"  smooth bezier, \
"___INPUT_FILE___"  using 1:2 with lines  title "IN, bit/s"  , \
"___INPUT_FILE___"  using 1:3 with lines  title "OUT, bit/s" smooth bezier, \
"___INPUT_FILE___"  using 1:3 with lines  title "OUT, bit/s"

Точка отсчета - без шейпера

Тест без шейперов


Для того что бы получить некоторую точку отсчета (учитывая что лаба - это ВМки) делаю первый прогон без ограничения трафика.


















Бесклассовые дисциплины

TBF

Про TBF много пишут но я никогда ее не использовал. Соответственно - нужно тестировать.
Как и все бесклассовые дисциплины крепиться или к листу (leaf) или к интерфейсу.
Об этом напишу подробнее ниже.
Напомню что eth1 - интерфейс в сторону node-1
Удаляем текущую дисциплину

tc qdis del dev eth1 root

Убеждаемся что удалена (т е стоит по умолчанию pfifo_fast)

tc qdisc s  dev eth1
qdisc pfifo_fast 0: root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc ingress ffff: parent ffff:fff1 ----------------
qdisc ingress ffff: parent ffff:fff1 ----------------

Второй раз удалить дисциплину по-умолчанию нельзя:

tc qdis del dev eth1 root
RTNETLINK answers: No such file or directory

Добавляем дисциплину tbf:

tc qdisc add dev eth1 root tbf rate 180kbit latency 20ms buffer 1540

Проверяем:

tc qdisc s  dev eth1
qdisc tbf 8002: root refcnt 2 rate 180000bit burst 1539b lat 20.0ms
qdisc ingress ffff: parent ffff:fff1 ----------------
Описание параметров

После длительного гугления я так и не нашел внятного описания параметров. Потому попробую процитировать

  • rate — ограничение скорости
  • latency — максимальный "возраст"пакета в очереди
  • burst — размер буфера. В байтах. (burst/buffer/maxburst - альтернативные названия что вносит некоторую путаницу)


Вот такое описание я нашел на Хабре, красным - мои вопросы
Дисциплина ТBF для своей работы использует механизм токенов. Токены генерируются системой с постоянной какой??? скоростью и помещаются в буфер(bucket). За каждый токен, вышедший из буфера с интерфейса уходит IP-пакет.А как насчет размера пакета? скорость передачи зависит от размера пакета Если скорости передачи пакетов и генерации токенов совпадает, процесс передачи данных идет без задержки. Если скорость передачи пакетов меньше чем скорость токенов, последние начинают накапливаться в буфере и затем могут использоваться для кратковременной передачи данных на скорости выше пороговой. Если скорость передачи пакетов выше — токенов начинает не хватать. Пакеты данных ожидают новых токенов некоторое время Какое? думаю - пока не заполнится очередь заданая limit/latency, а затем начинают отбрасываться.

Прямым следствием из этого я вижу следующее - если задать бурст ОЧЕНЬ большим то можно ожидать всплеска траффика в начале теста.
Впрочем немного погуглив - найдено другое описание алгоритма http://linux.die.net/man/8/tc-tbf

Результаты
tbf

Результаты (для меня) достаточно неожиданные

  • Таки да - достаточно четко выставлена нужная скорость
  • Явных потерь пингов я не наблюдаю
  • Рост задержек явно не соответствует обещанным 20мс но и не запредельный
64 bytes from node-2 (192.168.2.2): icmp_seq=19 ttl=63 time=84.5 ms
64 bytes from node-2 (192.168.2.2): icmp_seq=20 ttl=63 time=84.6 ms
64 bytes from node-2 (192.168.2.2): icmp_seq=21 ttl=63 time=82.2 ms
64 bytes from node-2 (192.168.2.2): icmp_seq=28 ttl=63 time=86.0 ms
64 bytes from node-2 (192.168.2.2): icmp_seq=30 ttl=63 time=84.3 ms
64 bytes from node-2 (192.168.2.2): icmp_seq=37 ttl=63 time=84.1 ms







Epic Fail
tc qdisc replace  dev eth1 root tbf rate 40Mbit   burst 159900000000000000 latency 10s

Kernel panic
Судя по моим подсчетам - burst 159900000000000000 (который пересчитывается в байты при создании правила) израсходовал 1100Мб при том что на ВМке всего1 гиг - предположительная причина - перерасход памяти

Проверка предположения про burst

Как я писал выше, предположение что установка огромного burst вызовет всплеск трафика в начале теста требует подтверждения: настраиваю следующим образор

tc qdisc replace  dev eth1 root tbf rate 40Mbit   burst 159900000  latency 10s
Tbf rate 40Mbit burst Max latency 10s.png

Как можно видеть по графику - предположение полностью подтверждается, наблюдаем явный пик трафика и потом переход к "нормальной скорости"

Проверка влияния burst и latency на поведение алгоритма

Попробуем собрать более-менее полную статистику по burst и latency. Для этого я в цикле прогоняю тесты при этом в каждом следующем тесте я делаю burst=burst*N что бы обеспечить более-менее приемлемую скорость перебора. Аналогично - для latency. Все параметры теста вынесены в заголовок графика.

001 tbf rate 102400kbit buffer 6160 latency 20ms.png
001 tbf rate 102400kbit buffer 98560 latency 20ms.png
001 tbf rate 102400kbit buffer 394240 latency 20ms.png
003 tbf rate 102400kbit buffer 25231360 latency 20ms.png
004 tbf rate 102400kbit buffer 413390602240 latency 5368709120ms.png
004 tbf rate 102400kbit buffer 6614249635840 latency 85899345920ms.png


Выводы

Судя по тому что я вижу - TBF неплохо подходит для простых случаев; хорошо масштабируемый до скоростей порядка 100Мбит. Задирание буферов до запредельных значений смысла не имеет как и увеличение latency.
Насколько я могу судить алгоритм достаточно точный - снимаемые с ноды значения соответвуют выставляемым на роутере.

Классовые дисциплины

Для простых случаев можно использовать и классовые дисциплины - при этом конструкции будут достаточно простые и понятные.

HTB

HFSC

http://ace-host.stuart.id.au/russell/files/tc/doc/sch_hfsc.txt

Источники