Перейти до вмісту

B6. Продуктивність і черги

просунутийспирається на модуль 2, модуль 12

Модуль 2 дає числа для пропускної здатності, затримки й добутку «смуга × затримка», а модуль 12 пояснює, чому TCP сам наповнює будь-яку чергу, яку йому дають. Ця робота показує обидва ефекти на стенді, де все під вашим контролем: канал на 10 Mbit/s, затримка 20 мс в обидва боки, втрати й різна довжина черги.

Після цієї роботи ви зможете:

  • побудувати ланцюжок netem → tbf на вихідному інтерфейсі маршрутизатора й пояснити, що в ньому робить кожна ланка;
  • виміряти пропускну здатність через iperf3 -J і прочитати з його виводу алгоритм перевантаження, пропускну здатність і повторні передачі;
  • порівняти CUBIC і BBR на чистому шляху й на шляху з втратами та пояснити різницю механізмом, а не словами «BBR швидший»;
  • виміряти затримку ping під навантаженням і побачити bufferbloat у числах;
  • замінити довгу FIFO-чергу на fq_codel і виміряти ефект;
  • подати результат у вигляді звіту, в якому кожне твердження стоїть на виміряному числі.

Так виглядає розбір скарги «відеодзвінок розвалюється, коли хтось завантажує файл»: швидкість каналу нормальна, а затримка в черзі на вузькому місці під навантаженням виростає на сотні мілісекунд.

Результат роботи: топологія з трьох просторів імен у кінцевому стані (netem + tbf + fq_codel), каталог results/ із замірами і report.md. Чекер перевіряє налаштування й наявність замірів, а не те, яку швидкість чи затримку ви отримали: на різних машинах числа різні.

Топологія. Назви просторів імен і адреси фіксовані, назви інтерфейсів ви обираєте самі.

b6-cli 10.66.1.2 ── 10.66.1.1 b6-rt 10.66.2.1 ── 10.66.2.2 b6-srv
Простір імен Адреси Роль
b6-cli 10.66.1.2/24 клієнт iperf3 і ping, маршрут за замовчуванням через 10.66.1.1
b6-rt 10.66.1.1/24, 10.66.2.1/24 маршрутизатор із вузьким місцем; ip_forward=1
b6-srv 10.66.2.2/24 сервер iperf3, маршрут за замовчуванням через 10.66.2.1

Кінцевий стан, який перевіряє чекер.

  • На інтерфейсі b6-rt з адресою 10.66.2.1 (у бік сервера): netem із затримкою 20 мс як коренева черга, під нею tbf rate 10mbit, а під tbf (як його дочірня черга) fq_codel.
  • На інтерфейсі b6-rt з адресою 10.66.1.1 (у бік клієнта): netem із затримкою 20 мс.
  • У каталозі results/ заміри, названі як у таблиці нижче.
  • У report.md сім розділів, названих як у таблиці.
Файл у results/ Що в ньому
*.json виводи iperf3 -J із клієнта b6-cli до 10.66.2.2; потрібен хоча б один із -C cubic і хоча б один із -C bbr
ping-idle.txt ping до 10.66.2.2 без навантаження
ping-load.txt ping до 10.66.2.2 під час iperf3, коли в tbf довга черга
ping-load-fqcodel.txt те саме після заміни черги на fq_codel
Розділ report.md (заголовок другого рівня) Вимога
## Топологія короткий опис, як побудовано
## Базова лінія числа: швидкість без netem, RTT без навантаження
## Затримка і втрати числа: що змінили затримка й втрати
## CUBIC і BBR числа: обидва алгоритми на чистому шляху й під втратами
## Bufferbloat числа: RTT під навантаженням проти RTT без нього
## fq_codel числа: те саме після заміни черги
## Висновки власними словами, що з чого випливає

У розділах із числами потрібні значення з одиницями (9.4 Mbit/s, 42 ms).

Чого робити не треба. Не підбирайте параметри, щоб «вийшла гарна картина»: вимірюйте те, що вийшло, і пояснюйте його. Складні профілі трафіку, tc filter, cake, ECN і tc-police до роботи не входять.

Обмеження. Швидкість каналу 10 Mbit/s і затримка 20 мс в кожен бік фіксовані, щоб числа різних студентів можна було порівнювати. Кожен замір тривалістю не менше 10 секунд.

Готово, коли sudo ./check.sh проходить усі перевірки, а в звіті кожне з тверджень таблиці «Що треба вміти підтвердити» стоїть на числі.

  • Прочитайте в модулі 2 розділ про добуток «смуга × затримка», а в модулі 12 розділи про чергу на вузькому місці, керування перевантаженням (CUBIC, BBR) і керування чергою (fq_codel).
  • Потрібні права root, iperf3, iproute2 (tc), python3. Їх ставить setup/provision.sh; вручну: sudo apt-get install iperf3 iproute2.
  • BBR має бути серед доступних алгоритмів: sysctl net.ipv4.tcp_available_congestion_control. Якщо в переліку немає bbr, виконайте sudo modprobe tcp_bbr.
  • Побудуйте топологію так, як у B2: три простори імен, дві пари veth, маршрути, ip_forward.
  • Каталог results/ і report.md тримайте там, звідки запускаєте check.sh.
  1. Топологія і базова лінія.

    Збудуйте топологію з таблиці вище. Кінці пар veth створюйте одразу у просторах імен, щоб у просторі господаря не лишалося зайвого.

    Виміряйте без жодного шейпінгу. Перший iperf3 — сервер у b6-srv, далі клієнт:

    Terminal window
    sudo ip netns exec b6-srv iperf3 -s
    sudo ip netns exec b6-cli iperf3 -c 10.66.2.2 -t 10 -J > results/baseline.json
    sudo ip netns exec b6-cli ping -c 15 -i 0.2 10.66.2.2 > results/ping-idle.txt

    Між замірами iperf3 чекайте кілька секунд: сервер обслуговує одного клієнта за раз і після завершення тесту ще кілька секунд не готовий до наступного.

    Перевірте: ping повертає відповіді з ttl=63 (пакет пройшов маршрутизатор), а базова швидкість на veth на порядки вища за ті 10 Mbit/s, що ви обмежите далі. Запишіть обидва числа.

  2. Вузьке місце: затримка й tbf.

    Тепер на інтерфейсі b6-rt у бік сервера зберіть ланцюжок. Кореневою ставите netem із затримкою, під нею ліміт швидкості:

    Terminal window
    sudo ip netns exec b6-rt tc qdisc add dev <до-сервера> root handle 1: netem delay 20ms
    sudo ip netns exec b6-rt tc qdisc add dev <до-сервера> parent 1:1 handle 10: \
    tbf rate 10mbit burst 32kbit latency 500ms
    sudo ip netns exec b6-rt tc qdisc add dev <до-клієнта> root netem delay 20ms

    netem сам не має ліміту швидкості, тому tbf стоїть під ним як дочірня черга. latency 500ms каже tbf, скільки найдовше пакет може простояти в черзі: це і є розмір буфера, приблизно 625 кБ при 10 Mbit/s. Навмисно завелика черга потрібна для етапу 4.

    Перевірте: tc qdisc show dev <до-сервера> показує обидві ланки, ping тепер дає приблизно 40 мс (два рази по 20 мс), а iperf3 із CUBIC упирається трохи нижче 10 Mbit/s. Поясніть, чому не точно 10 (заголовки, стартова фаза TCP) і чому ping до сервера показує 40, а не 20. Заміри збережіть: results/cubic.json, results/ping-idle.txt (перезапишіть: тепер це RTT з затримкою, але без навантаження).

    Перед цим запишіть у звіт добуток «смуга × затримка» для цього шляху: 10 Mbit/s × 40 мс дає 50 кБ у польоті. Порівняйте з буфером на 625 кБ.

  3. Втрати.

    Додайте до netem на інтерфейсі в бік сервера випадкові втрати 1 %:

    Terminal window
    sudo ip netns exec b6-rt tc qdisc change dev <до-сервера> root handle 1: netem delay 20ms loss 1%

    Виміряйте iperf3 із -C cubic і -C bbr (по 20 с, між ними пауза), збережіть як results/cubic-loss.json і results/bbr-loss.json. Прочитайте з JSON швидкість отримувача й кількість повторних передач (sum_sent.retransmits), а алгоритм підтвердіть полем end.sender_tcp_congestion.

    Порівняйте з чистим шляхом (cubic.json з етапу 2 і такий самий bbr.json). Поясніть різницю, спираючись на модуль 12: що кожен алгоритм вважає сигналом перевантаження.

    Після заміру поверніть втрати до нуля (loss 0% або netem delay 20ms без loss): інакше наступні етапи змішають два ефекти.

  4. Bufferbloat.

    Запустіть довге навантаження CUBIC (наприклад, 20 с) і під час нього з іншого термінала міряйте ping:

    Terminal window
    sudo ip netns exec b6-cli iperf3 -c 10.66.2.2 -t 20 -C cubic
    # в іншому терміналі, за кілька секунд після старту:
    sudo ip netns exec b6-cli ping -c 15 -i 0.3 10.66.2.2 > results/ping-load.txt

    Порівняйте середню й максимальну затримку з ping-idle.txt. Канал завантажено повністю, а затримка виросла: CUBIC наповнює чергу, поки не з’являться втрати, а черга на півсекунди дозволяє їй рости довго. Запишіть обидва числа й різницю в рази.

    Окремо подумайте, що це означає для користувача, чий голосовий дзвінок ділить з цим потоком той самий канал.

  5. fq_codel.

    Замініть довгу чергу tbf на fq_codel, залишивши обмеження швидкості на місці: fq_codel стає дочірньою чергою tbf (у прикладі з етапу 2 це parent 10:1):

    Terminal window
    sudo ip netns exec b6-rt tc qdisc replace dev <до-сервера> parent 10:1 handle 20: fq_codel

    Повторіть заміри з етапу 4 і збережіть results/ping-load-fqcodel.txt. Виміряйте також швидкість iperf3 і порівняйте з етапом 2: якою ціною досягнуто меншу затримку?

    Поясніть у звіті, що саме робить CoDel: він міряє час, який пакет провів у черзі, і скидає пакети, щоб TCP вчасно зменшив вікно, а fq дає кожному потоку окрему підчергу, тому потік ping не стоїть позаду потоку iperf3.

  6. Звіт.

    Складіть report.md за розділами з таблиці вище. Кожен розділ із числами мусить мати таблицю чи список значень з одиницями, а висновок пояснювати механізм: чому вийшло саме це.

З каталогу, де лежать results/ і report.md:

Terminal window
sudo /шлях/до/labs/b6-performance/check.sh
# або з явними шляхами:
sudo ./check.sh ~/b6/results ~/b6/report.md

Чекер нічого не будує. Він знаходить інтерфейси b6-rt за адресами, тому назви інтерфейсів не мають значення. Перевіряється:

  1. Топологія: адреси на місці, ip_forward=1, клієнт досягає сервера через маршрутизатор (TTL відповіді 63).
  2. Черги: у бік сервера діє tbf із швидкістю 10 Mbit/s; на обох інтерфейсах b6-rt є netem із затримкою; під tbf стоїть fq_codel.
  3. Живий тест: чекер сам запускає короткий iperf3 (порт 5299) і переконується, що швидкість не перевищує обмеження з запасом, тобто шейпер стоїть на шляху трафіку.
  4. Заміри: у results/ є JSON iperf3 із CUBIC і з BBR (алгоритм читається з поля sender_tcp_congestion, а адреси клієнта й сервера мають збігатися з топологією) і три файли ping.
  5. Звіт: у report.md усі сім розділів, розділи із замірами містять числа з одиницями.

Чекер не порівнює швидкості чи затримки з очікуваними: результат залежить від машини. Якщо ядро не має sch_netem чи sch_fq_codel, відповідні пункти чекер друкує як пропущені (--) і не рахує їх ні успіхом, ні помилкою.

Що треба вміти підтвердити

Section titled “Що треба вміти підтвердити”
Твердження Чим доводиться
Шейпер стоїть на шляху даних iperf3 не перевищує 10 Mbit/s
Затримка складається з двох netem ping ≈ 40 мс без навантаження
Черга на вузькому місці визначає затримку ping під навантаженням у рази вищий, ніж без нього
Алгоритм справді той sender_tcp_congestion у JSON
Втрати по-різному б’ють по CUBIC і BBR cubic-loss.json і bbr-loss.json
fq_codel зменшує затримку ping-load-fqcodel.txt проти ping-load.txt
Швидкість при цьому майже та сама iperf3 до і після

tc каже Specified qdisc kind is unknown. Ядро не має потрібного модуля (sch_netem, sch_fq_codel). Спробуйте sudo modprobe sch_netem, а якщо модуля немає зовсім (контейнер, мінімальне ядро), цей етап виконати не вийде: робіть його на віртуальній машині.

Шейпер стоїть не на тому інтерфейсі. Дані iperf3 -c (клієнт → сервер) йдуть через b6-rt у бік сервера, тож tbf має стояти саме там. Якщо поставити його в бік клієнта, він обмежуватиме лише квитанції, а швидкість лишиться гігабітною.

iperf3 із CUBIC і BBR міряли в різних умовах. Якщо між ними ви змінили чергу чи втрати, порівняння не має сенсу. Міняйте одну річ за раз.

iperf3: error - the server is busy running a test або обрив з’єднання. Попередній тест ще не завершився на боці сервера. Зачекайте кілька секунд.

ping під навантаженням запущено до iperf3 або після нього. Запускайте його через 2–3 секунди після старту тесту й зупиняйте до його кінця.

У tbf надто малий burst. Якщо burst менший за MTU, пакети не проходять взагалі; 32kbit (4 кБ) для цієї роботи підходить.

replace замість add для fq_codel. У tbf уже є дочірня черга (стандартна FIFO), тому її замінюють командою replace.

Порівняння «до і після» без повторів. Один прогін може відрізнятися від наступного на кілька відсотків. Повторіть заміри хоча б тричі й наведіть у звіті розкид.

Порівняйте з cake (потрібен sch_cake), який поєднує шейпер і керування чергою в одній ланці. Додайте ECN (ecn у fq_codel і sysctl net.ipv4.tcp_ecn=1) і подивіться, чи зменшилася кількість втрат. Змініть затримку до 100 мс і побачте, як від RTT залежить швидкість набору вікна у CUBIC і BBR. Побудуйте графік iperf3 -J за секундами (поле intervals) для кожного алгоритму.