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

Материал из noname.com.ua
Версия от 14:22, 12 марта 2020; Sirmax (обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к навигацииПерейти к поиску


Что почитать еще

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-2

  • 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"

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

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


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


















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

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

RED

Отличная документация: "Подробнее с RED можно ознакомится в исходниках ядра"

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

По-поводу HTB написано очень много - но вопросы с пониманием возникают постоянно. Потому я попробую собрать наиболее подробное и понятное описание из разных источников - такая компиляция.
Вот неплохое описание:
The Hierarchical Token Bucket (HTB) is an improved version of TBF that introduces the notion of classes. Each class is, in fact, a TBF-like qdisc, and classes are linked together as a tree, with a root and leaves. HTB introduces a number of features to improved the management of bandwidth, such as a the priority between classes, a way to borrow bandwidth from another class, or the possibility to plug another qdisc as an exit point (a SFQ for example).
Т.е. для начала считаем что HTB - это расширенная TBF с возможностью займа полосы и подключения к выходу других дисциплин.

Пробная настройка

У HTB много малопонятных параметров - я постараюсь описать их по возможности подробно.
ВАЖНО!!! Я НЕ использую никакую дисциплину в "листьях" - это тест ТОЛЬКО HTB

Первым делом создаем корневую дисциплину - у нее по сути есть всего 2 параметра

# tc qdisc add dev eth1 root handle 1: htb default 20
  • default 20 — задаем класс по-умолчанию. В нем будут обрабатываться пакеты, не попавшие в другие классы дисциплины htb.

Если его не указать, то будет назначен “default 0” и весь не классифицированный (не попавший под фильтры) трафик будет отправляться со скоростью интерфейса. В моем случае когда надо ограничить весь трафик (базовый случай - аналог примера выше) это будет единственный класс и никаких фильтров применяться не будет. (примеры с фильтрами, приоритетами и деревьями классов - ниже, в другом разделе этого документа)

  • r2q DRR quantums are computed as rate in Bps/r2q {10}

Есть несколько описаний но насколько я смог понять - это кванты трафика с которым работает HTB, очевидно что делать мелкие кванты при нынешних скоростях смысла нет. Приведу несколько описаний (автор - не я)

    • Второй параметр R2Q используется для квантования трафика в классах. В случае малых скоростей рекомендуется значение = 1, что позволяет шейпать с точностью до 4kbit. Если не указан, то =10, что для скоростей >120Kbit.


    • Сейчас стоит рассмотреть понятие квантов трафика. В процессе конкурентной передачи данных нескольких классов обслуживание каждого из них начинается после того, как обработано некоторое количество байт предыдущего класса. Это количество байт называется квантом (quantum). Когда несколько классов претендуют на канал родительского, они получают части канала пропорциональные их квантам. Важно знать, что расчёт распределения канала тем точнее, чем меньше размер кванта (но квант всё же должен быть не меньше величины MTU). Как правило нет необходимости задавать кванты вручную, поскольку HTB рассчитывает их самостоятельно. Размер кванта класса устанавливается (при создании или изменении класса) равным запрошенной скорости делённой на глобальный параметр r2q. По умолчанию r2q равен 10, что приемлемо для скоростей выше 15 kbps (120 kbit), поскольку обычно MTU равен 1500. Для меньших скоростей величина r2q равна 1; это подходит для скоростей от 12 kbit.При желании можно установить величину кванта вручную. В этом случае параметр r2q игнорируется. Будут выведены предупреждения о том, что установленная величина не верна, но ими можно пренебречь.


http://forum.nag.ru/forum/index.php?showtopic=48277&st=0&p=609502&#entry609502

    • Еще одно хорошее описание:

Уверен, многие сталкивались с проблемами:
HTB: quantum of class 10001 is big. Consider r2q change или HTB: quantum of class 10001 is small. Consider r2q change.


Что делать вообще и как жить? На удивление информации нереально мало.
Но на форму nag.ru нашелся чудесный челвоек technolab, который дал следующие разъяснения:


MTU - максимальный размера блока в байтах который может быть передан.
Quantum - число байт, которые может передать поток перед переходом к следующему классу, по умолчанию = MTU интерфейса. Расчет распределения канала тем точнее, чем меньше это значение.
R2Q - глобальный параметр, по умолчанию R2Q = 10, если Quantum указан, то R2Q игнорируется.


Немного констант:
quantum = rate / r2q
mtu ≤ quantum ≤ 60000


Соответственно:
quantum is small => RATE / R2Q < MTU
quantum is big => RATE / R2Q > 60000


То есть, для шейпинга на скорсоти около 30 000 мегабит у нас интервал r2q лежит в районе 700-3000. Ограничения - нельзя делать делать меньше mtu и нельзя делать уж очень большим.
Вот этот момент не очень понятен - при больших скоростях r2q надо брать достаточно большим что бы получался большой квантум - но как вычислили значения - не понятно
Пример с форума НАГа:

для примера на канал 900 мегабит
$TC->("qdisc add dev $dev root handle 1: htb r2q 37500");
автоматом будет посчитан quantum = 3000

ровно таким же макаром нужно считать для дочек 

Сбивает с толку размерность

  • mtu/mru - в байтах
  • quantum - как производная от mtu - тоже в байтах
  • rate/ceil тоже надо указывать в байтах соответвенно имеем:

(quantum=3000)*(r2q=37500) = (rate=112500000 Мбайт/с) = (rate= 112500000*8/1000/1000 = 900 Mbit)

Создаем класс и прикрепляем его к корню:

# tc class add dev eth1 parent 1: classid 1:20 htb rate 180kbit ceil 180kbit

прикрепляем к root qdisc класс с идентификатором 1:1. Тем самым ограничиваем скорость на интерфейсе до 180Кбайт/c.

  • classid 1:10 — идентификатор класса.
  • rate 180kbit — устанавливаем нижний порог пропускной способности для класса. (в нашем простейшем случае - значения равны )
  • ceil 180kbit — устанавливаем верхний порог пропускной способности для класса.
  • burst - не устанавливаю
  • cburst - не устанавливаю
  • prio 1 - приоритет, судя по документации классы работают в порядке приоритетов и пока есть трафик в классах с меньшим приоритетом классы с большим - не обрабатываются. Это утверждение требует проверки что будет сделано ниже - в классовых конфигурациях.
  • quantum - не задаю, в базовом тесте полагаюсь на авторассчет
  • mtu - я не нашел описание должен ли МТУ класса быть равным МТУ интерфейса или больше него - но много примеров устанавливают МТУ 1600 (против 1500 на интерфейсе)

Кстати, в документации указано, что по факту в HTB шейпинг трафика происходит только в краевых классах, в нашем случае 1:20. Что часто сбивает с толку. Но в нашем случае это не нужно.

Результаты

Результаты пробного теста достаточно интересны (хотя и предсказуемые)

  • Связь с сервером на время работы теста практически отсутствует, однако открыт вопрос - в каких таких буферах пинги стояли столько времени?




В качестве ответа на вопрос - следующая цитата:
Within the one HTB instance many classes may exist. Each of these classes contains another qdisc, by default tc-pfifo(8).
Т.е. сужествует qdisc по умолчанию и это pfifo c огромными (судя по пингу) очередями


64 bytes from node-1 (192.168.1.2): icmp_seq=51 ttl=63 time=65415 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=55 ttl=63 time=65388 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=56 ttl=63 time=65325 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=74 ttl=63 time=64448 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=88 ttl=63 time=64280 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=94 ttl=63 time=64150 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=100 ttl=63 time=65329 ms
From 192.168.2.1 icmp_seq=172 Destination Host Unreachable
From 192.168.2.1 icmp_seq=173 Destination Host Unreachable
From 192.168.2.1 icmp_seq=174 Destination Host Unreachable
From 192.168.2.1 icmp_seq=175 Destination Host Unreachable
64 bytes from node-1 (192.168.1.2): icmp_seq=139 ttl=63 time=65715 ms
  • Ограничение работает как и ожидалось
005 htb rate 180kbit default burst default cburst default quantum.png
  • burst и cburst имеют разумные для такой скорости значения по-умолчанию
tc -s c s dev eth1
class htb 1:20 root prio 0 rate 180000bit ceil 180000bit burst 1599b cburst 1599b
 Sent 4276815 bytes 3106 pkt (dropped 1977877, overlimits 0 requeues 0)
 rate 0bit 0pps backlog 0b 0p requeues 0
 lended: 3090 borrowed: 0 giants: 0
 tokens: 1081942 ctokens: 1081942
Повторное тестирование: разные скорости но настройки по-умолчанию

Для сбора статистики повторяем тест с разными скоростями

RATE=1
for I in `seq 1 7`
do
  let RATE=RATE*2
  tc qdis del root dev eth1
  tc qdisc replace  dev  eth1 root  handle 1:0 htb default 20
  tc class add dev eth1 parent 1: classid 1:20 htb rate ${RATE}Mbit ceil ${RATE}Mbit
...
done

Результат соответствует ожиданию - шейпер успешно отработал на скорости от 2Мбит до 128Мбит при автоматическом вычислении всех параметров, с ростом скоростей уменьшались только задержки пингов.
Приведу только 2 крайних примера:

  • 2 Mbit
005 htb rate 2Mbit default burst default cburst default quantum.png
64 bytes from node-1 (192.168.1.2): icmp_seq=1 ttl=63 time=6007 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=3 ttl=63 time=5997 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=4 ttl=63 time=5995 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=5 ttl=63 time=5996 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=14 ttl=63 time=5982 ms
  • 128Mbit
005 htb rate 128Mbit default burst default cburst default quantum.png
64 bytes from node-1 (192.168.1.2): icmp_seq=504 ttl=63 time=105 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=506 ttl=63 time=103 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=510 ttl=63 time=101 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=512 ttl=63 time=100 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=513 ttl=63 time=101 ms
64 bytes from node-1 (192.168.1.2): icmp_seq=514 ttl=63 time=101 ms



HTB
Burst cburst
  • burst - это просто размер буффера в токенах и он должен быть достаточным, сверхбольшое его увеличение ничего не дает.
  • cburst - аналог peack rate т.е. размер буфера токенов который будет использоваться при превышении над ceil.


Небольшая цитата:
Сетевое устройство может передавать только один пакет в один момент времени и только с определенной устройством скоростью. Программам разделения канала остается только использовать эти параметры для расчетов деления канала на полосы требуемого размера. Таким образом, текущая и максимальная скорости передачи данных не могут быть урегулированы мгновенно. Они рассчитываются на основании усредненных данных о скорости отсылки пакетов. В действительности передача данных с учетом заданных свойств классов происходит следующим образом: устройству передается некоторое количество пакетов одного класса (которые отправляются в сеть со скоростью, определенной устройством, то есть максимально возможной), после чего некоторое время обрабатываются пакеты остальных классов. Параметры класса burst и cburst определяют количество данных, которое можно передать на максимальной скорости (скорости оборудования), после чего переключиться на обслуживание других классов.
Чем меньше параметр cburst (в идеале он должен быть равен размеру одного пакета), тем лучше он сглаживает ускорение передачи данных, чтобы скорость передачи не превысила величину ceil. Так же действует параметр peakrate дисциплины TBF.
Если параметр burst родительского класса меньше, чем у какого-нибудь из потомков, можно ожидать, что передача данных этого класса иногда будет останавливаться (так как дочерний класс пытается создать большее ускорение, чем позволено родительскому). HTB помнит о неудачной попытке ускорения в течение минуты.
Возникает вопрос: для чего нужно регулировать ускорение? Дело в том, что это дешевый и простой способ улучшить время отклика на переполненных каналах. К резким колебания склонен, к примеру, веб-трафик. Вы запрашиваете страницу, создавая ускорение, потом читаете ее. За время чтения “накапливается энергия” для следующего ускорения.
Параметры burst и cburst всегда должны быть не меньше, чем такие же параметры дочерних классов.
Оперируя высокими скоростями на компьютере с низкой частотой таймера, необходимо минимизировать величины burst и cburst для всех классов. Интервал срабатывания таймера равен 10 ms для архитектуры i386 и 1 ms для Alpha. Минимальное эффективное ускорение рассчитывается по формуле (максимальная скорость)*(интервал таймера). Например, чтобы обеспечить скорость 10 mbit на компьютере i386 параметр burst должен быть равен 12kb.
Заниженная величина burst приведет к тому, что данные будут передаваться на скорости, которая ниже запрошенной параметром rate. Последние версии tc по умолчанию самостоятельно рассчитывают и устанавливают минимальное значение burst.


С моей точки зрения практически во всех случаях можно положиться на автоматический расчет burst
При задирании burst/cburst поведение ожидаемое

007 htb rate 1Mbit default burst 409600 cburst 409600 quantum.png

Отмечу что выстрелить себе в ногу htb не дает - burst нельзя поставить выше определенного (но мне неизвестного) значения и занять всю память - похоже что при превышении "лишние" знаки отбрасываются =)

HTB + TBF vs HTB + pfifo (default qdisc)

В этом тесте я пробую следующие конфигуации

  • HTB с qdisc по-умолчанию (pfifo)
BASE_BUFFER=1540
BASE_LATENCY=20
RATE=1
BURST=1600
tc qdis del root dev eth1
tc qdisc replace  dev  eth1 root  handle 1:0 htb default 20
tc class add dev eth1 parent 1: classid 1:20 htb rate ${RATE}Mbit ceil ${RATE}Mbit burst ${BURST} cburst ${BURST}
008 htb rate 1Mbit default burst 1600 cburst 1600 quantum no leaf qdisc.png


  • HTB + TBF, скорость qdisc = скорости htb leaf class
tc qdis del root dev eth1
tc qdisc replace  dev  eth1 root  handle 1:0 htb default 20
tc class add dev eth1 parent 1: classid 1:20 htb rate ${RATE}Mbit ceil ${RATE}Mbit burst ${BURST} cburst ${BURST}
tc qdisc add dev eth1 parent 1:20  tbf rate ${RATE}Mbit    buffer ${BASE_BUFFER} latency ${BASE_LATENCY}ms
008 htb rate 1Mbit default burst 1600 cburst 1600 quantum tbf leaf.png


  • HTB + TBF, скорость qdisc в 2 раза больше скорости htb leaf class
tc qdis del root dev eth1
tc qdisc replace  dev  eth1 root  handle 1:0 htb default 20
tc class add dev eth1 parent 1: classid 1:20 htb rate ${RATE}Mbit ceil ${RATE}Mbit burst ${BURST} cburst ${BURST}
let RATE=RATE*2
tc qdisc add dev eth1 parent 1:20  tbf rate ${RATE}Mbit    buffer ${BASE_BUFFER} latency ${BASE_LATENCY}ms
008 htb rate 1Mbit default burst 1600 cburst 1600 quantum tbf leaf rate2.png


  • HTB + TBF, скорость qdisc в 32 раза больше скорости htb leaf class
tc qdis del root dev eth1
tc qdisc replace  dev  eth1 root  handle 1:0 htb default 20
tc class add dev eth1 parent 1: classid 1:20 htb rate ${RATE}Mbit ceil ${RATE}Mbit burst ${BURST} cburst ${BURST}
let RATE=RATE*32
tc qdisc add dev eth1 parent 1:20  tbf rate ${RATE}Mbit    buffer ${BASE_BUFFER} latency ${BASE_LATENCY}ms
008 htb rate 1Mbit default burst 1600 cburst 1600 quantum tbf leaf rate32.png
tc qdis del root dev eth1
tc qdisc replace  dev  eth1 root  handle 1:0 htb default 20
tc class add dev eth1 parent 1: classid 1:20 htb rate ${RATE}Mbit ceil ${RATE}Mbit burst ${BURST} cburst ${BURST}
let RATE=RATE*128
tc qdisc add dev eth1 parent 1:20  tbf rate ${RATE}Mbit    buffer ${BASE_BUFFER} latency ${BASE_LATENCY}ms
HTB + SFQ

SFQ ( как я ВНЕЗАПНО узнал ) имеет достаточно большое число параметров


http://stuff.onse.fi/man?program=tc-sfq&section=8



  • PARAMETERS
    • divisor: Can be used to set a different hash table size, available from kernel 2.6.39 onwards. The specified divisor must be a power of two and cannot be larger than 65536. Default value: 1024.размер хеша, предположительно он должен быть не меньше числа flow
    • limit: Upper limit of the SFQ. Can be used to reduce the default length of 127 packets. After linux-3.3, it can be raised.По сути - длинна буфера
    • depth: Limit of packets per flow (after linux-3.3). Default to 127 and can be lowered.Этот параметр отвечает за то какая часть общего буфера определнного limit может быть отдана каждому flow
    • perturb: Interval in seconds for queue algorithm perturbation. Defaults to 0, which means that no perturbation occurs. Do not set too low for each perturbation may cause some packet reordering or losses. Advised value: 60 This value has no effect when externalflow classification is used. Its better to increase divisor value to lower risk of hash collisions.как часто делать ре-хеш
    • quantum: Amount of bytes a flow is allowed to dequeue during a round of the round robin process. Defaults to the MTU of the interface which is also the advised value and the minimum value.квантум - порция данных которыми оперировать - делать кратным МТУ
    • flows: After linux-3.3, it is possible to change the default limit of flows. Default value is 127Число флоу
    • headdrop: Default SFQ behavior is to perform tail-drop of packets from a flow. You can ask a headdrop instead, as this is known to pro-vide a better feedback for TCP flows.
    • redflowlimit: Configure the optional RED module on top of each SFQ flow. Random Early Detection principle is to perform packet marks or drops in a probabilistic way. (man tc-red for details aboutRED). redflowlimit configures the hard limit on the real (not average) queue size per SFQ flow in bytes.
    • min: Average queue size at which marking becomes a possibility. Defaults to max /3
    • max: At this average queue size, the marking probability is maximal. Defaults to redflowlimit /4
    • probability: Maximum probability for marking, specified as a floating point number from 0.0 to 1.0. Default value is 0.02
    • avpkt: Specified in bytes. Used with burst to determine the time constant for average queue size calculations. Default value is 1000
    • burst: Used for determining how fast the average queue size is influenced by the real queue size.Default value is : (2 * min + max) / (3 * avpkt)
    • ecn: RED can either 'mark' or 'drop'. Explicit Congestion Notification allows RED to notify remote hosts that their rate exceeds the amount of bandwidth available. Non-ECN capable hosts can only be notified by dropping a packet. If this parameter is specified, packets which indicate that their hosts honor ECN will only be marked and not dropped, unless the queue size hits depth packets.
    • harddrop: If average flow queue size is above max bytes, this parameter forces a drop instead of ecn marking.


  • HTB + SFQ

Попробуем разные параметры
При установке flows=1 - получаем поведение FIFO с коротким буфером (depth не может быть больше 127)
Ожидаемое поведение - при нагрузке получим потери пинга близко к 100%

[root@router0 ~]# tc -s -d q s dev eth1
qdisc htb 1: root refcnt 2 r2q 10 default 20 direct_packets_stat 0 ver 3.17
 Sent 28253598 bytes 19524 pkt (dropped 44841, overlimits 73764 requeues 0)
 backlog 0b 0p requeues 0
qdisc sfq 40: parent 1:20 limit 127p quantum 1514b depth 127 flows 1/1024 divisor 1024 perturb 10sec
 Sent 28253598 bytes 19524 pkt (dropped 44841, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0

Собственно это мы и наблюдаем: даже АРП перестал ходить.

From router0 (192.168.2.1) icmp_seq=218 Destination Host Unreachable
From router0 (192.168.2.1) icmp_seq=219 Destination Host Unreachable

Пробую указать divisor=1
Видно что flows=1 (что логично - нет смысла создавать неиспользуемые потоки)

[root@router0 ~]# tc -s -d q s dev eth1
qdisc htb 1: root refcnt 2 r2q 10 default 20 direct_packets_stat 0 ver 3.17
 Sent 28419225 bytes 19618 pkt (dropped 201715, overlimits 240233 requeues 0)
 backlog 0b 0p requeues 0
qdisc sfq 40: parent 1:20 limit 127p quantum 1514b depth 127 flows 1/1 divisor 1 perturb 10sec
 Sent 28419225 bytes 19618 pkt (dropped 201715, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0

Поведение отличается но не сильно:

245 packets transmitted, 60 received, +9 errors, 75% packet loss, time 246003ms

Вывод - для того что бы SFQ распределял полосу равномерно между потоками нужно создавать достаточное число потоков и при этом - не слишком много что бы буффер (limit) не был слишком большим - иначе время ожидания становится запредельным.

tc -s -d q s dev eth1
qdisc htb 1: root refcnt 2 r2q 10 default 20 direct_packets_stat 0 ver 3.17
 Sent 48001878 bytes 33888 pkt (dropped 220259, overlimits 280718 requeues 0)
 backlog 0b 0p requeues 0
qdisc sfq 40: parent 1:20 limit 65024p quantum 1514b depth 127 flows 512/16384 divisor 16384 perturb 1sec
 Sent 48001878 bytes 33888 pkt (dropped 220259, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0
011 htb rate 1Mbit default burst 1600 cburst 1600 quantum sfq perturb 1 limit 65536 flows 512 depth 127 divisor 16384.png
HFSC

Подробнее о настройке - в другом разделе, тут только пример жеского шефпера который просто ограничивает скорость

DEV=eth1

tc qdis del root dev ${DEV}
tc qdisc replace  dev  eth1 root  handle 1:0 hfsc default 1
tc class add dev ${DEV} parent 1:0 classid 1:1 hfsc rt m2 1Mbit m2 

QOS - обеспечение приоритетов одного трафика над другим

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

HFSC

Перенесено --> http://wiki.sirmax.noname.com.ua/index.php/Linux_QOS_HFSC

Источники






SFQ

U32