Ограничение скорости передачи трафика. Policer или shaper, что использовать в сети?
Когда речь заходит об ограничении пропускной способности на сетевом оборудовании, в первую очередь в голову приходят две технологи: policer и shaper. Policer ограничивает скорость за счёт отбрасывания «лишних» пакетов, которые приводят к превышению заданной скорости. Shaper пытается сгладить скорость до нужного значения путём буферизации пакетов. Данную статью я решил написать после прочтения заметки в блоге Ивана Пепельняка (Ivan Pepelnjak). В ней в очередной раз поднимался вопрос: что лучше – policer или shaper. И как часто бывает с такими вопросами, ответ на него: всё зависит от ситуации, так как у каждой из технологий есть свои плюсы и минусы. Я решил разобраться с этим чуточку подробнее, путём проведения нехитрых экспериментов. Полученные результаты подкатом.
И так, начнём с общей картинки разницы между policer и shaper.
Как видно, policer срезает все пики, shaper же делает сглаживание нашего трафика. Достаточно неплохое сравнение между policer и shaper можно найти здесь.
Может стоило сделать проще?Скорость сессии обычно меряется в отведённый промежуток времени, например, за 5 сек или 5 минут. Брать мгновенное значение бессмысленно, так как данные всегда передаются на скорости канала. При этом если мы будем делать усреднение за разные временные интервалы, мы получим разные графики скорости передачи данных, так как трафик в сети не равномерный. Я думаю, любой с этим сталкивался, строя графики в системе мониторинга.
Механизм токенов позволяет обеспечить гибкость в настройке ограничения скорости. Размер ведра влияет на то, как мы будем усреднять нашу скорость. Если ведро большое (т.е. токенов там может скопиться много), мы позволим трафику сильнее «выпрыгивать» за отведенные ограничения в определённые моменты времени (эквивалент усреднения на большем промежутке времени). Если размер ведра маленький, то трафик будет более равномерный, крайне редко превышая заданный порог (эквивалент усреднения на маленьком промежутке времени).
В случае policer’а наполнение ведра происходит каждый раз, когда приходит новый пакет. Количество токенов, которые загружаются в ведро, зависит от заданной скорости policer’а и времени, прошедшего с момента поступления последнего пакета. Если токенов в ведре нет, policer может отбросить пакеты или, например, перемаркировать их (назначить новые значения DSCP или IPP). В случае shaper’а наполнение ведра происходит через равные промежутки времени независимо от прихода пакетов. Если токенов не хватает, пакеты попадают в специальную очередь, где ждут появления токенов. За счёт этого имеем сглаживание. Но если пакетов приходит слишком много, очередь shaper’а в конечном счёте переполняется и пакеты начинают отбрасываться. Стоит отметить, что приведённое описание является упрощённым, так как и policer и shaper имеют вариации (детальный разбор данных технологий займёт объём отдельной статьи).
Эксперимент
Сначала посмотрим на работу policer. Настроим ограничение скорости равным 20 Мбит/с.
Конфигурация устройстваpolicy-map Policer_20
class class-default
police 20000000
interface GigabitEthernet0/0/1
service-policy output Policer_20
Используем автоматически выставляемое значение размера ведра токенов (token bucket). Для нашей скорости – это 625 000 байт. В iPerf запускаем генерацию трафика в рамках четырёх потоков, используя протокол TCP.
C:\Users\user>iperf3.exe -c 192.168.115.2 -t 20 -i 20 -P 4 Connecting to host 192.168.115.2, port 5201 [ 4] local 192.168.20.8 port 55542 connected to 192.168.115.2 port 5201 [ 6] local 192.168.20.8 port 55543 connected to 192.168.115.2 port 5201 [ 8] local 192.168.20.8 port 55544 connected to 192.168.115.2 port 5201 [ 10] local 192.168.20.8 port 55545 connected to 192.168.115.2 port 5201 [ ID] Interval Transfer Bandwidth [ 4] 0.00-20.01 sec 10.2 MBytes 4.28 Mbits/sec [ 6] 0.00-20.01 sec 10.6 MBytes 4.44 Mbits/sec [ 8] 0.00-20.01 sec 8.98 MBytes 3.77 Mbits/sec [ 10] 0.00-20.01 sec 11.1 MBytes 4.64 Mbits/sec [SUM] 0.00-20.01 sec 40.9 MBytes 17.1 Mbits/sec
Средняя скорость составила 17.1 Мбит/с. Каждая сессия получила разную пропускную способность. Обусловлено это тем, что настроенный в нашем случае policer не различает потоки и отбрасывает любые пакеты, которые превышают заданное значение скорости.
С помощью Wireshark собираем дамп трафика и строим график передачи данных, полученный на стороне отправителя.
Чёрная линия показывают суммарный трафик. Разноцветные линии – трафик каждого потока TCP. Прежде чем делать какие-то выводы и углубляться в вопрос, давайте посмотрим, что у нас получится, если policer заменить на shaper.
Настроим shaper на ограничение скорости 20 Мбит/с.
Конфигурация устройстваpolicy-map Shaper_20
class class-default
shape average 20000000
queue-limit 200 packets
interface GigabitEthernet0/0/1
service-policy output Shaper_20
При настройке используем автоматическое выставляемое значение размера ведра токенов BC и BE равное 8000. Но меняем размер очереди с 83 (по умолчанию в версии IOS XE 15.6(1)S2) на 200. Сделано это сознательно, чтобы получить более чёткую картину, характерную для shaper’а. На этом вопросе мы остановимся более подробно в подкате «Влияет ли глубина очереди на нашу сессию?».
cbs-rtr-4000#sh policy-map interface gigabitEthernet 0/0/1
Service-policy output: Shaper_20
Class-map: class-default (match-all)
34525 packets, 50387212 bytes
5 minute offered rate 1103000 bps, drop rate 0000 bps
Match: any
Queueing
queue limit 200 packets
(queue depth/total drops/no-buffer drops) 0/0/0
(pkts output/bytes output) 34525/50387212
shape (average) cir 20000000, bc 80000, be 80000
target shape rate 20000000
В iPerf запускаем генерацию трафика в рамках четырёх потоков, используя протокол TCP.
C:\Users\user>iperf3.exe -c 192.168.115.2 -t 20 -i 20 -P 4 Connecting to host 192.168.115.2, port 5201 [ 4] local 192.168.20.8 port 62104 connected to 192.168.115.2 port 5201 [ 6] local 192.168.20.8 port 62105 connected to 192.168.115.2 port 5201 [ 8] local 192.168.20.8 port 62106 connected to 192.168.115.2 port 5201 [ 10] local 192.168.20.8 port 62107 connected to 192.168.115.2 port 5201 [ ID] Interval Transfer Bandwidth [ 4] 0.00-20.00 sec 11.6 MBytes 4.85 Mbits/sec [ 6] 0.00-20.00 sec 11.5 MBytes 4.83 Mbits/sec [ 8] 0.00-20.00 sec 11.5 MBytes 4.83 Mbits/sec [ 10] 0.00-20.00 sec 11.5 MBytes 4.83 Mbits/sec [SUM] 0.00-20.00 sec 46.1 MBytes 19.3 Mbits/sec
Средняя скорость составила 19.3 Мбит/с. При этом каждый поток TCP получил примерно одинаковую пропускную способность.
С помощью Wireshark собираем дамп трафика и строим график передачи данных, полученный на стороне отправителя.
Чёрная линия показывают суммарный трафик. Разноцветные линии – трафик каждого потока TCP.
Сделаем первые промежуточные выводы:
- В случае policer полезная пропускная способность составила 17.1 Мбит/с. Каждый поток в разные моменты времени имел разную пропускную способность.
- В случае shaper полезная пропускная способность составила 19.3 Мбит/с. Все потоки имели примерно одинаковую пропускную способность.
Посмотрим более детально на поведение TCP сессии в случае работы policer и shaper. Благо, в Wireshark достаточно инструментов, чтобы сделать такой анализ.
Начнём c графиков, на которых отображаются пакеты с привязкой ко времени их передачи. Первый график – policer’а, второй – shaper’а.
Из графиков видно, что пакеты в случае shaper передаются более равномерно по времени. При этом в случае policer видны скачкообразные разгоны сессии и периоды пауз.
Анализ TCP сессии при работе policer
Посмотрим поближе на сессию TCP. Будем рассматривать случай policer’а.
Протокол TCP в своей работе опирается на достаточно большой набор алгоритмов. Среди них для нас наиболее интересными являются алгоритмы, отвечающие за управление перегрузками (congestion control). Именно они отвечают за скорость передачи данных в рамках сессии. ПК, на котором запускался iPerf, работает под управлением Windows 10. В Windows 10 в качестве такого алгоритма используется Compound TCP (CTCP). CTCP в своей работе позаимствовал достаточно многое из алгоритма TCP Reno. Поэтому при анализе TCP сессии достаточно удобно посматривать на картинку с состояниями сессии при работе алгоритма TCP Reno.
На следующей картинке представлен начальный сегмент передачи данных.
- На первом этапе у нас устанавливается TCP сессия (происходит тройное рукопожатие).
- Далее начинается разгон TCP сессии. Работает алгоритм TCP slow-start. По умолчанию значение окна перегрузки (congestion window — cwnd) для TCP-сессии в Windows 10 равно объёму десяти максимальных сегментов данных TCP сессии (MSS). Это означает, что данный ПК может отправить сразу 10 пакетов, не дожидаясь получения подтверждения на них в виде ACK. В качестве начального значения порога прекращения работы алгоритма slow-start (ssthresh) и перехода в режим избегания перегрузки (congestion avoidence) берётся значение максимального окна, которое предоставил получатель (advertised window — awnd). В нашем случае ssthresh=awnd=64K. Awnd – максимальное значение данных, которые получатель готов принять себе в буфер. Где посмотреть начальные данные сессии?Чтобы посмотреть параметры TCP, можно воспользоваться PowerShell.
Смотрим, какой глобальный шаблон TCP используется в нашей системе по умолчанию.
Далее выполняем запрос «Get-NetTCPSetting Internet» и ищем значение величины InitialCongestionWindow(MSS).
Значение awnd можно найти в пакетах ACK, пришедших от получателя:
В режиме TCP slow-start размер окна (cwnd) увеличивается каждый раз при получении ACK. При этом оно не может превысить значение awnd. За счёт такого поведения, мы имеем практически экспоненциальный рост количества передаваемых пакетов. Наша TCP сессия разгоняется достаточно агрессивно.- ПК устанавливает TCP-соединение (№1-3).
- Отправляет 10 пакетов (№4-13), не дожидаясь подтверждения (ACK), так как cwnd=10*MSS.
- Получает ACK (№14), который подтверждает сразу два пакета (№4-5).
- Увеличивает размер окна Cwnd=(10+2)*MSS=12*MSS.
- Отправляет дополнительно три пакета (№15-17). По идее ПК должен был отправить четыре пакета: два, так как он получил подтверждение на два пакета, которые были переданы ранее; плюс два пакета из-за увеличения окна. Но в реальности на самом первом этапе система шлёт (2N-1) пакетов. Найти ответ на этот вопрос мне не удалось. Если кто-то подскажет, буду благодарен.
- Получает два ACK (№18-19). Первое ACK подтверждает получение удалённой стороной четырёх пакетов (№6-9). Второе — трёх (№10-12).
- Увеличивает размер окна Cwnd=(12+7)*MSS=19*MSS.
- Отправляет 14 пакетов (№20-33): семь новых пакетов, так как получили ACK на семь ранее переданных пакетов, и ещё семь новых пакетов, так как увеличилось окно.
- И так далее.
- Policer никак не препятствует разгону сессии. Токенов в ведре много (при инициализации policer’а ведро заполнено токенами полностью). Для скорости 20 Мбит/с размер ведра по умолчанию выставляется равным 625000 байт. Таким образом, сессия разгоняется в момент времени практически до 18 Мбит/с (а мы помним, что у нас таких сессий четыре). Размер окна cwnd достигает максимального значения и становится равным awnd, а значит, cwnd = ssthersh. cwnd = ssthersh
Когда cwnd = ssthersh точного ответа, произойдёт ли смена алгоритма с slow-start на алгоритм congestion avoidance, я найти не смог. RFC точного ответа не даёт. С практической точки зрения это не очень важно, так как размер окна дальше расти не может.
- Так как наша сессия разогналась достаточно сильно, токены очень быстро тратятся и в конечном итоге заканчиваются. Ведро не успевает наполнятся (наполнение токенами идёт для скорости 20 Мбит/с, при этом суммарная утилизация всеми четырьмя сессиями в моменте времени приближается к 80 Мбит/с). Policer начинает отбрасывать пакеты. А значит, до удалённой стороны они не доходят. Получатель шлёт Duplicate ACK (Dup ACK), которые сигнализируют отправителю, что произошла потеря пакетов и нужно передать их заново.
После получения трёх Dup ACK наша TCP сессия переходит в фазу восстановления после потери (loss recovery, включающую алгоритмы Fast Retransmit/Fast Recovery). Отправитель устанавливает новое значение ssthresh = cwnd/2 (32K) и делает окно cwnd = ssthresh+3*MSS. - Отправитель пытается сразу же начать заново передать потерянные пакеты (работает алгоритм TCP Fast Retransmission). При этом продолжают приходить Dup ACK, назначение которых — искусственно увеличить окно cwnd. Это нужно, чтобы как можно быстрее восстановить скорость сессии из-за потери пакетов. За счёт Dup ACK окно cwnd вырастает до максимального значения (awnd).
Как только было отправлено количество пакетов, укладывающихся в окно cwnd, система останавливается. Для продолжения передачи данных ей нужны новые ACK (не Dup ACK). Но ACK не приходят. Все повторные пакеты отбрасываются policer’ом, так в ведре закончились токены, а времени, чтобы их восполнить, прошло слишком мало.
- В таком состоянии система ждёт, пока не сработает таймаут на получение нового ACK от удалённой стороны (Retransmission timeout — RTO). С этим как раз и связаны наши большие паузы, которые видны на графиках.
- После срабатывания таймера RTO система переходит в режим slow-start и устанавливает ssthresh = FlightSize/2 (где FlightSize – количество не подтверждённых данных), а окно cwnd = 1*MSS. Далее снова делается попытка передать потерянные пакеты. Правда, теперь отправляется всего один пакет, так как cwnd = 1*MSS.
- Так как в течение некоторого времени система ничего не передавала, в нашем ведре успели накопиться токены. Поэтому в конечном итоге пакет доходит до получателя. А значит, мы получим новое ACK. С этого момента система начинает передать потерянные ранее пакеты в режиме slow-start. Происходит разгон сессии. Как только размер окна cwnd превышает значение ssthresh, сессия переходит в режим congestion avoidance.
В алгоритме Compound TCP для регулирования скорости передачи используется окно отправителя (sending window — wnd), которое зависит от двух взвешенных величин: окна перегрузки (cwnd) и окна задержки (delay window — dwnd). Cwnd, как и раньше, зависит от полученных ACK, dwnd зависит от величины задержки RTT (round trip time). Окно wnd растёт только один раз за период времени RTT. Как мы помним, в случае slow-start окно cwnd росло при получении каждого ACK. Поэтому в режиме congestion avoidance сессия разгоняется не так быстро.
- Как только сессия разгоняется достаточно сильно (когда пакетов передаётся больше, чем есть токенов в ведре), опять срабатывает policer. Начинают отбрасываться пакеты. Далее следует фаза loss recovery. Т.е. весь процесс повторяется заново. И так продолжается, пока у нас не завершится передача всех данных.
TCP сессия при работе policer выглядит как лестница (идёт фаза передачи, за которой следует пауза).
Анализ TCP сессии при работе shaper
Теперь давайте посмотрим поближе на сегмент передачи данных для случая shaper. Для наглядности возьмём аналогичный масштаб, как и для графика policer на Рис.6.
Из графика мы видим всё ту же лесенку. Но размер ступенек стал существенно меньше. Однако если приглядеться к графику на Рис. 10, мы не увидим небольших «волн» на конце каждой ступеньки, как это было на Рис. 9. Такие «волны» были следствием потери пакетов и попыток их передачи заново.
Рассмотрим начальный сегмент передачи данных для случая shaper.
Происходит установление сессии. Далее начинается разгон в режиме TCP slow-start. Но этот разгон более пологий и имеет ярко выраженные паузы, которые увеличиваются в размере. Более пологий разгон обусловлен тем, что размер ведра по умолчанию для shaper всего (BC+BE) = 20 000 байт. В то время как для policer размер ведра — 625 000 байт. Поэтому shaper срабатывает существенно раньше. Пакеты начинают попадать в очередь. Растёт задержка от отправителя к получателю, и ACK приходят позже, чем это было в случае policer. Окно растёт существенно медленнее. Получается, что чем больше система передаёт пакетов, тем больше их накапливается в очереди, а значит, тем больше задержка в получении ACK. Имеем процесс саморегуляции.
Через некоторое время окно cwnd достигает значения awnd. Но к этому моменту у нас накапливается достаточно ощутимая задержка из-за наличия очереди. В конечном итоге при достижении определённого значения RTT наступает равновесное состояние, когда скорость сессии больше не меняется и достигает максимального значения для данного RTT. В моём примере среднее RTT равно 107 мс, awnd=64512 байт, следовательно, максимальная скорость сессии будет соответствовать awnd/RTT= 4.82 Мбит/с. Примерно такое значение нам и выдал iPerf при измерениях.
Но откуда берутся ярко выраженные паузы в передаче? Давайте посмотрим на график передачи пакетов через устройство с shaper в случае, если у нас всего одна TCP сессия (Рис.12). Напомню, что в нашем эксперименте передача данных происходит в рамках четырёх TCP сессий.
На этом графике очень хорошо видно, что нет никаких пауз. Из этого можно сделать вывод, что паузы на Рис.10 и 11 обусловлены тем, что у нас одновременно передаётся четыре потока, а очередь в shaper одна (тип очереди FIFO).
На Рис.13 представлено расположение пакетов разных сессий в очереди FIFO. Так как пакеты передаются пачками, они будут располагаться в очереди таким же образом. В связи с этим задержка между поступлением пакетов на приёмной стороне будет двух типов: T1 и T2 (где T2 существенно превосходит T1). Общее значение RTT для всех пакетов будет одинаковым, но пакеты будут приходить пачками, разнесёнными по времени на значение T2. Вот и получаются паузы, так как в момент времени T2 никакие ACK к отправителю не приходят, при этом окно сессии остаётся неизменным (имеет максимальное значение равное awnd).Очередь WFQЛогично предположить, что, если заменить одну общую очередь FIFO на несколько для каждой сессии, никаких ярко выраженных пауз не будет. Для такой задачи нам подойдёт, например, очередь типа Weighted Fair Queuing (WFQ). В ней для каждой сессии создаётся своя очередь пакетов.
policy-map Shaper
class shaper_class
shape average 20000000
queue-limit 200 packets
fair-queue
Из общего графика мы сразу видим, что графики всех четырёх TCP сессий идентичны. Т.е. все они получили одинаковую пропускную способность.
А вот и наш график распределения пакетов по времени передачи ровно в том же масштабе, что и на Рис. 11. Никаких пауз нет.
Стоит отметить, что очередь типа WFQ позволит нам получить не только более равномерное распределение пропускной способности, но и предотвратить «забивание» одного типа трафика другим. Мы всё время говорили про TCP, но в сети также присутствует и UDP трафик. UDP не имеет механизмов подстройки скорости передачи (flow control, congestion control). Из-за этого UDP трафик может с лёгкостью забить нашу общую очередь FIFO в shaper’е, что драматически повлияет на передачу TCP. Напомню, что, когда очередь FIFO полностью заполнена пакетами, по умолчанию начинает работать механизм tail-drop, при котором отбрасываются все вновь пришедшие пакеты. Если у нас настроена очередь WFQ, каждая сессия пережидает момент буферизации в своей очереди, а значит, сессии TCP будут отделены от сессий UDP.
Самый главный вывод, который можно сделать после анализов графиков передачи пакетов при работе shaper’а – у нас нет потерянных пакетов. Из-за увеличения RTT скорость сессии адаптируется к скорости shaper’а. Влияет ли глубина очереди на нашу сессию?Конечно! Изначально (если кто-то об этом ещё помнит) мы изменили глубину очереди с 83 (значение по умолчанию) на 200 пакетов. Сделали мы это для того, чтобы очереди хватило для получения достаточного значения RTT, при котором суммарная скорость сессий становиться примерно равна 20 Мбит/с. А значит, пакеты «не вываливаются» из очереди shaper’а.
При глубине в 83 пакета очередь переполняется быстрее, нежели достигается нужное значение RTT. Пакеты отбрасываются. Особенно ярко это проявляется на начальном этапе, когда у нас работает механизм TCP slow-start (сессия разгоняется максимально агрессивно). Стоит отметить, что количество отброшенных пакетов несравнимо меньше, чем в случае с policer, так как увеличение RTT приводит к тому, что скорость сессии растёт более плавно. Как мы помним, в алгоритме CTCP размер окна в том числе зависит от значения RTT.
Графики утилизации пропускной способности и задержки при работе policer и shaper
В заключение нашего небольшого исследования построим ещё несколько общих графиков, после чего перейдём к анализу полученных данных.
График утилизации пропускной способности:
В случае policer мы видим скачкообразный график: сессия разгоняется, потом наступают потери, и её скорость падает. После чего всё повторяется снова. В случае shaper наша сессия получает примерно одинаковую пропускную способность на протяжении всей передачи. Скорость сессии регулируется за счёт увеличения значения RTT. На обоих графиках вначале можно наблюдать взрывной рост. Он обусловлен тем, что наши вёдра изначально полностью заполнены токенами и TCP-сессия, ничем не сдерживаемая, разгоняется до относительно больших значений (в случае shaper это значение в 2 раза меньше).
График задержки RTT для policer и shaper (по-хорошему, это первое о чём мы вспоминаем, когда говорим про shaper):
В случае policer (первый график) задержка RTT для большинства пакетов минимальна, порядка 5 мс. На графике также присутствуют существенные скачки (до 340 мс). Это как раз моменты, когда пакеты отбрасывались и передавались заново. Тут стоит отметить, как Wireshark считает RTT для TCP трафика. RTT – это время между отправкой оригинального пакета и получением на него ACK. В связи с этим, если оригинальный пакет был потерян и система передавала пакет повторно, значение RTT растёт, так как точкой отсчёта является в любом случае момент отправки оригинального пакета.
В случае shaper задержка RTT для большинства пакетов составила 107 мс, так как они все задерживаются в очереди. Есть пики до 190 мс.
Выводы
Итак, какие итоговые выводы можно сделать. Кто-то может заметить, что это и так понятно. Но наша цель была копнуть чуточку глубже. Напомню, что в эксперименте анализировалось поведение TCP-сессий.
- Shaper предоставляет нам на 13% больше полезной пропускной способности, чем policer (19.3 против 17.1 Мбит/с) при заданном ограничении в 20 Мбит/с.
- В случае shaper’а пропускная способность распределяется более равномерно между сессиями. Наилучший показатель может быть получен при включении очереди WFQ. При работе policer’а присутствуют существенные пики и падения скорости для каждой сессии.
- При работе shaper’а потерь пакетов практически нет (конечно, это зависит от ситуации и глубины очереди). При работе policer’а мы имеем существенные потери пакетов – 12.7%.
Если policer настроен ближе к получателю, наша сеть фактически занимается прокачкой бесполезного трафика, который будет в итоге отброшен policer’ом. Например, в разрезе глобальной сети интернет это может является проблемой, так как трафик режется зачастую ближе к получателю.
- В случае shaper’а у нас появляется задержка (в нашем эксперименте – это дополнительные 102 мс). Если трафик примерно одинаков, без существенных всплесков, очередь shaper’а находится в относительно стабильном состоянии и больших вариаций в задержке (jitter) не будет. Если трафик будет иметь взрывной характер, мы можем получить повышенное значение jitter.
Вообще наличие очереди может достаточно негативно сказываться на работе приложений – так называемый эффект излишней сетевой буферизации (Bufferbloat). Поэтому с глубиной очереди надо быть аккуратными.
- Благодаря разным типам очередей shaper позволяет нам учитывать приоритезацию трафика при ограничении скорости. И если встаёт необходимость отбрасывать пакеты, в первую очередь делать это для менее приоритетных. В policer’е добиться этого сложнее, а для некоторых схем невозможно.
- Policer и shaper подвержены ситуации, когда UDP трафик может «забить» TCP. При настройке этих технологий необходимо учитывать данный факт.
- Работа shaper’а создаёт бОльшую нагрузку на сетевое устройство, чем работа policer’а. Как минимум требуется память под очередь.
Можно отметить ещё один факт, хоть и не относящийся непосредственно к задаче ограничения скорости. Shaper позволяет нам настраивать различные типы очередей (FIFO, WFQ и пр.), обеспечивая тем самым разнообразные уровни приоритезации трафика при его отправке через устройство. Это очень удобно в случаях, если фактическая скорость передачи трафика отличается от канальной (например, так часто бывает с выходом в интернет или WAN каналами).Исследование влияния policer в сети интернетВ этом году при поддержке Google было проведено исследование, в котором анализировался негативный эффект работы policer’а в сети интернет. Было определено, что от 2% до 7% потерь видео трафика по всему Миру вызвано срабатыванием policer’а. Потери пакетов при непосредственной работе policer’а составили порядка 21%, что в 6 раз больше, чем для трафика, который не подвержен срабатыванию данной технологии. Качество видео трафика, который подвергся обработке policer’ом, хуже, чем в случае, если policer не срабатывал.
Для борьбы с негативным эффектом работы policer’а предлагаются следующие меры в зависимости от точки их применения.
Для интернет-провайдеров:
- В policer’е уменьшить размер ведра (burst size). Это приведёт к тому, что TCP сессия не сможет слишком сильно разогнаться, пока есть свободные токены, и быстрее начнёт адаптацию под реальную пропускную способность.
- Вместо policer’а использовать shaper (с небольшой глубиной очереди).
- Использовать и shaper, и policer одновременно. В этом случае shaper располагается чуть раньше, чем policer. Shaper задерживает пакеты, сглаживая колебания. Из-за такой задержки policer успевает аккумулировать достаточное количество токенов, чтобы передавать трафик. Потери в таком случае минимизируются.
Однозначных рекомендаций по поводу конфигурации shaper в документе не даётся. Shaper может обеспечивать положительный эффект как при большом, так и при маленьком значении размера ведра (даже если BC = 8 000 байт). Также нет однозначной рекомендации по поводу глубины очереди. Маленькая глубина приводит к лишним потерям, большая может негативно сказаться на задержках в сети. Во всех случаях есть свои плюсы и минусы.
Для контент-провайдеров предлагается ограничивать скорость отправки трафика на сервере, чтобы избегать включения policer’а. Но на практике оценить реальную скорость канала не всегда просто. Второй метод — избегать взрывной передачи трафика за счёт модификации алгоритмов TCP: использовать TCP Pacing (отправлять пакеты с привязкой к RTT, а не к моменту получения ACK) и изменить схему работы фазы loss recovery (на каждый полученный ACK слать только один новый пакет).
Таким образом, нет однозначного ответа на вопрос, что лучше использовать: shaper или policer. Каждая технология имеет свои плюсы и минусы. Для кого-то дополнительная задержка и нагрузка на оборудование не так критична, как для другого. А значит выбор делается в сторону shaper. Кому-то важно минимизировать сетевую буферизацию для борьбы с джиттером – значит наша технология policer. В ряде случаев вообще можно использовать одновременно обе эти технологии. Поэтому выбор технологии зависит от каждой конкретной ситуации в сети.
Причесываем трафик — динамический шейпер на Linux / Habr
Предположим у вас есть домашняя сеть (или не домашняя, а сеть небольшого офиса) с выходом в интернет через не очень скоростной канал. А пользователей — много, и каждый хочет что-то скачивать, да с максимальной скоростью. Вот тут перед нами встатет задача, как максимально эффективно распределить наш интернет-канал между пользователями так, чтобы они не мешали друг другу. В этой статье я опишу, как можно решить такую задачу с помощью Linux-сервера.
Сформулируем, что же мы хотим получить в результате:
1. Чтобы канал поровну делился между пользователями.
2. Чтобы канал зря не простаивал.
3. Чтобы онлайн-игры, ssh и telnet не «лагали» даже при полной загрузке канала, например торрентами.
Если интернетом будут одновременно пользоваться 10 пользователей — каждый получит в свое распоряжение 1/10 часть канала, если в данный момент активен только один пользователь — он будет использовать весь канал сам.
Добиться этого можно используя планировщик пакетов HTB, который входит в ядро linux начиная с версии 2.4.20.
Можно конфигурировать шейпер с помощью команды tc, но для более удобной и наглядной настройки я рекомендую скачать скрипт htb.init. Они использует для конфигурации htb набор конфигурационных файлов, именуемых так, что при сортировке по алфавиту их имена позволяют визуально представить себе дерево классов шейпера и удобно его редактировать.
Предположим, что у нас на сервере есть интерфейс eth0, через который мы подключены к интернет, и eth2, который «смотрит» в локальную сеть.
Управлять можно только исходящим из интерфейса трафиком, поэтому для eth0 будут правила для upload трафика пользователей, а для — eth2 — download трафика.
По умолчанию конфигурационные файлы htb.init находятся в /etc/htb/. Для начала напишем правила шейпинга для upload трафика, они у нас будут простые.
Создаем файл с именем eth0 (интерейс «смотрящий» в интернет), в него напищем следующие строки:DEFAULT=20
R2Q=1
Параметр DEFAULT задает номер класса, к которому будет относиться трафик «по умолчанию» — обычно это класс с минимальным приоритетом. Параметр R2Q влияет на работу алгоритма разделения канала и зависит от ширины канала. Я подбирал его значение эмпирическим путем, для моего исходящего канала в 2 Mbit.
Далее, создадим файл eth0-2.full2MBit, для класса включающего в себя весь доступный интернет-канал. Имя файла состоит из имени интерфейса и id класса, после точки идет смысловое имя класса, используется как комментарий и системой игнорируется.RATE=2Mbit
CEIL=2Mbit
RATE — это наша гарантированная полоса, CEIL — максимальная полоса. Так как у меня канал с гарантированной максимальной полосой в 2 Mbit, то эти параметры у меня равны.
Теперь мы создадим по одному файлу для каждого класса трафика, который у нас будет. Я у себя создал отдельные классы для ssh трафика, а так же трафика игр World Of Warcraft и Counter Strike, хотя вы можете сделать для всего высокоприоритетного трафика один класс.
Пример для ssh — создаем файл eth0-2:10.ssh. В имени файла через двоеточие указан id родительского класса 2 и id текущего класса — 10. Идентификаторы для класса вы можете выбирать произвольно.# class for outgoing ssh
RATE=128Kbit
CEIL=2Mbit
RULE=*:22
PRIO=1
BURST=100Kb
В параметре RATE указана гарантированная полоса для этого класса, в CEIL — максимальная. Мы выделяем для ssh 128 KBit (как минимум) и разрешаем ему загрузить весь канал (я закачивать файлы по sftp). PRIO задает приоритет класса трафика (1- максимальный, чем больше число — тем меньш приоритет). BURST задает максимальный объем трафика, который будет передан на максимальной скорости перед тем, как перейти к передаче данных из дургих классов. Установив этот параметр в достаточно высокое значение мы добиваемся того, что трафик ssh будет передан с минимальными задержками.
RULE задает правило, по которому будет отбираться трафик в этот класс.
Формат — RULE=[[saddr[/prefix]][:port[/mask]],][daddr[/prefix]][:port[/mask]]
Обратите внимание на запятую! RULE=*:22 обозначает трафик, у которого порт назначения 22, а RULE=*:22, обозначает трафик, у которого исходящий порт — 22.
Создадим так же классы для других видов трафика, и класс для трафика «по умолчанию» с id 20 (мы указали вначале что именно в класс номер 20 надо направлять трафик «по умолчанию»). В нем укажем используемую дисциплину разделения канала LEAF=sfq, для того чтобы upload поровну делился между TCP сессиями разных пользователей.
Для eth2 правила будут почти такие же, только с учетом что общая ширина канала — 100 Mbit, мы ведь хотим чтобы можно было обращаться к локальным ресурсам сервера на полной скорости, для интернет-трафика выделен отдельный класс на 2 MBit, у которого как потомки добавлены классы отдельных пользователей, разделение по классам я делал по IP адресам. Для каждого пользователя можно указать максимальную и гарантированную скорость, а так же приоритет.
После правки конфигурации перезапускаем htb.init:/etc/init.d/htb.init restart
И правила шейпинга трафика сразу же вступают в силу.
В процессе состевления правил обычно возникает необходимость как-то визуализировать трафик, в целях отладки и мониторинга, поэтому решил написать плагин для системы мониторинга серверов munin, который бы визуализировал распределение по классам HTB трафика. Выводить решил загрузку только классов-листьев дерева, так как именно они обычно несут смысловую нагрузку.
Скачать плагин вы можете из официального репозитория плагинов munin, называется он qos_, просто скопируйте его в папку плагинов munin /usr/share/munin/plugins/ и в папке используемых плагинов /etc/munin/plugins сделайте на него символическую ссылку вида qos_eth2, где eth2 — имя интерфейса, на котором нужно мониторить загрузку.
В файле конфигурации плагинов можно добавить следущее:[qos_eth2]
env.ignore_queue1_10 yes
env.label_name1_31 Viperet
env.label_name1_32 Cornet
Параметр env.ignore_queue позволяет не отображать на графике состояние класса с указанным id, а параметр env.label_name — задать человекопонятную метку для класса на графике.
В итоге должно получиться что то такое:
Хочу заметить, что у меня несколько нетипичная ситуация, два интернет канала на 2 и 1 Mbit, и для каждого пользователя ограничение в 2 Mbit скорости загрузки, поэтому на графике видно, что если активен один пользователь — его скорость урезается на 2 Mbit, а если несколько — суммарная скорость может достигать и трех. На таком достаточно «тесном» канале работают более 20 человек, и вполне комфортно себя чувствуют, не мешая друг другу.
Эта картинка с реально действующего сервера, и она обновляется каждые 5 минут и отображает актуальную картину загрузки канала.
UPD: выложил пример конфига htb.init
Обзор USB-модулей ZyXEL Keenetic Plus, функций шейпера и IntelliQoS / Сети и коммуникации
В обзоре ZyXEL Keenetic Ultra II и Giga III, которые нам очень понравились, мы обещали познакомить наших читателей с дополнительной функциональностью этих новинок. Что же, пора исполнять данное обещание, благо за полтора месяца с момента выхода предыдущего материала разработчики успели выпустить несколько обновлений прошивок и довезти до тестовой лаборатории модули ZyXEL Keenetic Plus DECT и DSL. Для начала познакомимся с функциями шейпера и IntelliQoS, помогающими управлять шириной пропускания канала. Во второй части материала подробнее рассмотрим DECT-базу для организации домашней SIP-телефонии и опробуем в деле DSL-модуль, который позволяет подключаться к ADSL2(+)/VDSL2-провайдерам и создавать прямые VDSL2-соединения между маршрутизаторами посредством телефонной линии.
ZyXEL Keenetic Giga III с модулями Keenetic Plus DSL и DECT
⇡#Шейпер и IntelliQoS
Стоит сразу отметить, что некоторые пользователи путают функцию шейпинга трафика с функцией QoS (англ. quality of service — «качество обслуживания»). В представленном ZyXEL варианте шейпера нет никакой приоритизации трафика, это именно ограничение пропускной способности канала у заданного клиента. Говоря проще, пользователь может указать для выбранных устройств и сегментов локальной сети максимальную доступную им скорость доступа в Интернет. Обратите внимание, что речь идёт именно о верхнем пороге, выше которого они не смогут «прыгнуть», а не о гарантированной скорости доступа. Да-да, всё как у любого интернет-провайдера, который в своих заманчивых тарифах скромно указывает мелким шрифтом, что покупателю будет доступно, к примеру, не «ровно 100 Мбит/c», а всего лишь «до 100 Мбит/с», ну а дальше уж как повезёт. Например, если у вас есть канал 50 Мбит/с, а одному из клиентов выставлено ограничение в 10 Мбит/с, то оставшиеся 40 Мбит/с будут отданы остальным пользователям. Если на таком же канале для пяти клиентов выставить лимит в 20 Мбит/с каждому, то, конечно, никакого чуда не произойдёт – канал в итоге всё равно будет делиться между всеми.
Ограничение скорости для отдельного клиента и для гостевой беспроводной сети |
Одной из важнейших особенностей шейпера в серии Keenetic, по словам создателей, является то, что, несмотря на чисто программную реализацию, он весьма экономно относится к имеющимся ресурсам CPU роутера, не слишком сильно нагружая его. Так что пользоваться им без проблем можно будет и на младших Keenetic’ах. Например, на Omni II загрузка CPU с включенным шейпером в среднем на пару процентов выше, чем без оного. Впрочем, если клиент за шейпером ничего не потребляет, то и нагрузки на процессор тоже нет. Важно отметить, что клиенты за шейпером никак не влияют на пропускную способность других потребителей трафика, и те могут, например, использовать аппаратное ускорение NAT. Такая схема, по словам разработчиков, намного эффективнее конкурирующих решений. В видео ниже приведена короткая демонстрация работы шейпера – сначала для проверки скачиваем свежий дистрибутив без всяких ограничений, а затем последовательно меняем лимиты скорости для нашего клиента, попутно наблюдая за тем, как резво меняется скорость в торрент-клиенте в зависимости от заданных лимитов.
Пример работы шейпера на ZyXEL Keenetic Ultra II
Функция IntelliQoS также использует шейпер. При её включении маршрутизатор автоматически анализирует текущий трафик, разбирая пакеты (DPI, Deep Packet Inspection) и определяя, сколько и какого именно контента потребляют пользователи в данный момент. А затем делает одну простую вещь – динамически ограничивает наиболее неуёмные в своих сетевых аппетитах приложения с помощью шейпера так, чтобы они не мешали прохождению видеотрафика, который наиболее чувствителен к любым затыкам в Сети. Речь идёт в первую очередь об обеспечении бесперебойного проигрывания видеопотока с онлайн-хостингов вроде YouTube, Vimeo, Megogo и других, но так, чтобы и другие пользователи не чувствовали себя совсем уж ущемлёнными. Больше всего проблем пользователям, согласно статистике ZyXEL, доставляет BitTorrent, который при удачном стечении обстоятельств – а в случае, например, с популярными сериалами (естественно, легальными, что вы такое говорите?!) оно всегда удачно – способен полностью забить и так-то не очень широкий канал. Впрочем, из собственного опыта заметим, что, когда домашние пытаются выкачать очередной апдейт к онлайн-игре гигабайт эдак на тридцать в официальном клиенте, который хоть прямо в этом и не признаётся, но всё же построен на базе BitTorrent то сетевая жизнь остальных и на вполне приличном стомегабитном канале становится ох какой тяжкой.
Настройки IntelliQoS |
Интереснее всего устроена работа DPI – в ZyXEL реализовали функцию распознавания типов трафика с нуля, а в дальнейшем она будет выделена в отдельный продукт. Тонких деталей реализации алгоритмов DPI создатели не раскрывают, но в общих чертах выглядит это примерно так – анализу подвергаются потоки трафика с момента инициализации соединения. Собственно говоря, уже на этом этапе можно распознать или хотя бы предположить, что это за трафик, анализируя, например, DNS-запросы или наблюдая за процессом «рукопожатия» между клиентом и сервером при установке соединения. Впрочем, в первую очередь рассматривается именно сам поток и его особенности – частоты встречаемости символов и их последовательностей, нюансы структуры пакетов/кадров, общий характер протекания потока и так далее. В дальнейшем классификация идёт примерно по 20 признакам, которые группируются в массив из порядка 400 элементов. Сочетание отдельных элементов массива для текущего потока – естественно, с некой долей вероятности – указывает, что этот поток принадлежит к такому-то типу приложений/классу трафика.
Характерные срезы на графике скоростей – результат использования шейпера в реальном времени
Затем эта информация передаётся другим компонентам ПО роутера, которые используют их по своему усмотрению. Система IntelliQoS как раз и получает информацию о том, что, к примеру, такой-то хост включил торрент-клиент и отъел слишком большой кусок интернет-канала, что может помешать другому хосту, который обратится к Vimeo. Так что первый хост неплохо было бы урезонить, и IntelliQoS передаёт соответствующую команду шейперу. Даже если никто не смотрит видео прямо сейчас, хосту с включенным торрент-клиентом всё равно отдаётся 80% ширины канала, чтобы у других потребителей онлайн-видео смогло хотя бы запуститься. Любопытно, что для определения типа трафика, по словам разработчиков ZyXEL, требуется всего-то порядка 30 первых пакетов и около одного килобайта RAM для каждого потока. После этого трафик по возможности передаётся обратно на аппаратный уровень для ускорения работы – от обычных HW NAT с WMM до коммутаторов с поддержкой аппаратного ускорения и приоритизации, если таковые имеются, а запись о его типе сохраняется в отдельный файл, где она и находится до завершения потока.
Классификатор трафика пополняется в полуавтоматическом режиме на стороне разработчиков, а затем регулярно передаётся на маршрутизаторы вместе с обновлением прошивки. Для включения шейпера необходимо установить соответствующий компонент, а затем в списке подключенных клиентов выбрать нужного и выставить ограничение скорости. Для задействования функции IntelliQoS достаточно включить одну галочку и указать скорость доступа в Сеть согласно тарифу – всё остальное роутер сделает сам. Обе функции пока доступны только в свежих прошивках NDMS 2.06 для Giga III и Ultra II. Шейпер также имеется во всех прошивках версии 2.05 для моделей Ultra, Giga II, Keenetic II, Viva, Extra, Omni II, Lite III и других. А вот IntelliQoS достанется только некоторым старшим моделям из этого ряда. Шейпер и IntelliQoS рассчитаны в основном на пользователей с не очень быстрым интернет-каналом, которым хочется одновременно и IPTV смотреть, и любимые торренты качать, и веб-сёрфингом заниматься.
Если Вы заметили ошибку — выделите ее мышью и нажмите CTRL+ENTER.
Шейпер для Linux в пользовательском пространстве (NFQUEUE-based) / Habr
Времена узких интернет-каналов постепенно уходят в прошлое, но иногда еще бывает нужно шейпить сетевой трафик. В Linux для этого есть соответствующие механизмы ядра и утилиты для управления механизмами. Все это хозяйство довольно сложно устроено, обычно постижение шейпинга занимает не один день. Хотя, в простых случаях можно накопипастить заклинания tc из статей или найти скрипт, который эти заклинания генерирует.Как человеку любознательному, всегда было интересно, можно ли сделать процесс настройки шейпинга для небольших сетей проще? Можно ли хотя бы грубо детектировать важный трафик и отделять его от неважного без DPI и сигнатурного анализа? Можно ли шейпить трафик в любых направлениях без создания псевдо-интерфейсов или добавления модулей в ядро? И вот, после некоторых размышлений и гуглежа, решил написать простой шейпер в userspace. Чтоб попробовать ответить на вопросы экспериментом.
В результате эксперимента получилась вот такая штука github.com/vmxdev/damper
Работает штука приблизительно так:
При старте создаются два программных потока. В первом NFQUEUE захватывает пакеты, они анализируются, каждому пакету назначается «вес» (или приоритет) и он сохраняется в очереди с приоритетами. Когда очередь заполнена, пакеты с низким приоритетом затираются высокоприоритетными. Другой поток выбирает пакеты с наибольшим весом и помечает их к отправке. Отправка происходит с ограниченной скоростью, из-за этого собственно и получается шейпирование.
Небольшое отступление о механизме NFQUEUE
Этот механизм позволяет копировать сетевые пакеты в пользовательское пространство для обработки. Приложение, которое слушает соответствующую очередь, должно вынести вердикт относительно пакета (пропустить или отбросить). Кроме этого допускается изменение пакета. Этим механизмом пользуются IDS/IPS типа Snort или Suricata. Пакеты помечаются для обработки в iptables, цель NFQUEUE. То есть мы можем выбрать любое направление (входящий трафик, исходящий, транзитный, или, скажем, UDP с порта 666 на порт 13) и направить его в шейпер. Там пакеты будут анализироваться, возможно изменять свой порядок, а при превышении лимита самые низкоприоритетные будут отбрасываться.
Первые рабочие версии шейпера захватывали пакеты, помещали их в очередь и потом ре-инъектировали в сырой (raw) сокет. На StackOverflow и некоторых других статьях пишут что это единственный способ задерживать пакеты перед перепосылкой. Конструкция работала, но товарищ Vel разъяснил, где можно задерживать пакет прямо в NFQUEUE, настройка шейпера упростилась.
Модули
Так как шейпер экспериментальный, я сделал его не монолитным, а «модульным». В каждом модуле вычисляется вес пакета по разным критериям. Из коробки есть 4 модуля, но можно легко написать еще какой-нибудь. Модули можно использовать вместе, можно по отдельности.
Модули:
- inhibit_big_flows — подавляет большие потоки. Чем больше передано байт между двумя IP-адресами, тем меньшим становится «вес» пакета. То есть повышается вероятность того что пакет из большой тяжелой сессии будет отброшен. Информация хранится в кольцевом буфере, так что время от времени наступает амнистия (количество отслеживаемых сессий задается в конфиге), потоки замещаются более свежими
- bymark — вес пакетов задается по марке. iptables-ом выставляется марка по каким-то критериям, для этих пакетов будет применяться коэффициент, указанный в конфиге. Можно вручную поднять или понизить приоритет какого-то отмаркированного трафика
- entropy — вес считается в зависимости от энтропии (точнее, мере энтропии по Шеннону) потока. Поток идентифицируется номером протокола и адресами участников. Для TCP/UDP учитывается еще и порт источника и назначения. Чем выше энтропия, тем меньше вес. Т.е. мультимедиа, шифрованный, сжатый трафик отбрасывается с большей вероятностью чем остальной.
- И очень примитивный модуль random — просто добавляет случайности в процесс отброса и переупорядочивания пакетов (если использовать только этот модуль, получится классический RED).
Веса пакетов, измеренные в каждом модуле, умножаются на коэффициент(каждому модулю можно задать свой) и складываются. Получается результирующий вес.
Статистика и графики
Шейпер умеет вести статистику и рисовать графики. Вживую это выглядит так: damper.xenoeye.com. Зеленый — сколько пропущено байт/пакетов, красный — сколько отброшено. График можно позумить/поскроллить.
Второй график (включается директивой «wchart yes» в конфиге) — средние веса пакетов за секунду, отнормированные, с разбивкой по модулям.
Демо работает на не очень быстрых ARMах (Scaleway bare metal, 32-битные ARMv7), иногда может слегка залипать.
Отладка
У модулей inhibit_big_flows и entropy есть отладочный режим, включается в конфиге. В этом режиме модули каждые N секунд делают дамп текущих потоков с весами.
Кроме этого есть режим без ограничения скорости («limit no» в конфиге). В этом режиме все пакеты пропускаются (без анализа в модулях), но можно вести статистику прошедних пакетов/байт, медитировать на график загрузки канала, например.
Результаты
Шейпер получился достаточно простой (ну, на мой, замыленный, взгляд). Для использования нужно выбрать направление по которому шейпить, добавить правило iptables, выставить в конфиге нужную скорость и запустить.
Тяжелые и высокоэнтропийные сессии определяются и понижаются в приоритете, но чудес не бывает: если канал очень узкий, комфортного серфинга не получится.
На больших скоростях и большом количестве пользователей я его не тестировал, но на десятках мегабит и с несколькими пользователями субъективно получается лучше чем без шейпера. Хотя он грузит CPU, но это не только от использования NFQUEUE, а еще и от общей корявости кода (и немного от особенностей clock_nanosleep()), можно отпимизировать и оптимизировать.
Это, конечно, только proof of concepts, код местами сумбурный и практически не причесывался.
Если у кого-то есть соображения, пожелания и предложения по поводу, было бы интересно почитать.
Linux под нагрузкой. Высокопроизводительный шейпер / Habr
В прошлой заметке мы рассматривали некоторые аспекты тюнинга роутера под Linux, предназначенного для работы в условиях высоких нагрузок: Linux под нагрузкой. Маршрутизатор, NAT-сервер Теперь же речь пойдет о шейперах.Ограничение скорости прохождения трафика (шейпинг) является достаточно ресурсоемкой задачей. Поэтому, при наличии в сети хотябы нескольких сотен абонентов, и при наличии больших объемов проходящего трафика, вопрос оптимизации шейперов встает особенно остро.
Рассматривать будем шейпер под управлением Linux: эта ОС показала наилучшие результаты по производительности в условиях высоких нагрузок.
Короткое введение
Шейпер — дисциплина обслуживания очереди пакетов. Дисциплина может быть с классами и без оных. С классами — значит, что трафик может быть “зашейпен” в соответствии с определенным классом.
Какой трафик каким классом шейпится – определяет фильтр.
Говоря проще, имеем два дерева: дерево фильтров и дерево классов. Фильтры раскидывают по определеным критериям трафик на классы. В классах трафик приоретизируется или шейпится в соответствии с заданными в классах параметрами.
С хешами и без хешей
Как любое дерево, дерево фильтров становится слишком ресурсо-затратным при достижении определенного порога.
Когда пакет от какого-то IP-адреса попадает на дерево фильтров, он начинает сравниваться с критериями каждого фильтра. При совпадении, пакет отправляется в соответствующий класс. Т.е. для каждого пришедшего пакета производится последовательно проверка на предмет соответствия критерию каждого фильтра в дереве до тех пор, пока не произойдет совпадение.
Например, для сети по 24-й маске у нас будет в среднем 128 шагов для каждого пакета при поиске нужного для него класса.
Это несущественно при небольших объемах трафика и при небольшом кол-ве абонентов. Когда же абонентов десятки тысяч, а в интернет уходят гигабиты, такой подход становится просто невозможным – сервер шейпинга банально не будет справляться с нагрузкой.
Если все дерево – это последовательность проверок на IP-адрес, то гораздо эффективнее будет задействовать хеши. Хеш — это таблица соответствий неких “значений” неким “ключам”. В нашем случае ключеом выступает IP-адрес, а значением – фильтр, направляющий пакет в свой класс.
Таким образом, по ключу (IP-адресу) мы быстро находим нужный фильтр для пакета, – в 1 шаг.
Собственно, про использование хешей статей уже написано немало – это не является “чем-то военным”. Можно обратиться к первоисточнику.
Скрипт для построения шейпера
Сильно облегчить жизнь при построении шейперов может вот такой вот Fast U32 hashing filter generator – это программа на Си, написанная румынским (?) сисадмином.
На вход ей даются следующие параметры:
- prefix.in – список префиксов и соответствующих им классов в формате <префикс> <класс>
- u32filters.out – выходной файл, сюда будут сохраняться фильтры
- interface – имя интерфейса, на котором будет строиться шейпер
- src/dst – направление потока (входящий или исходящий)
- batch – если этот параметр указан, выходной файл будет генерироваться пригодным для запуска tc –b
Подробные примеры можно посмотреть на странице проекта выше.
Строго говоря, вам не нужно особенно глубоко вникать в суть работы данной программы – в данном случае вам не придется иметь с ней дело.
Для удобства я написал небольшой скрипт, который на основе заданной конфигурации строит таблицы префиксов и классов, запускает упомянутую выше программу для построения фильтров с нужными параметрами, из всего имеющегося добра строит готовую конфигурацию шейпера и запускает его через tc –b.
Все что требуется – указать некоторые конфигурационные параметры в файле.
Конфигурация скрипта
В папке скрипта есть следующие папки и файлы:
- data – здесь будут располагаться промежуточные результаты работы скрипта, а так же конечная конфигурация шейпера: _classes – готовый конфиг шейпера, _filters – фильтры с хешами, _prefixes – таблица соответствий префиксов классам, _speeds – соответствие классов скоростям
- lib – необходимые для работы библиотеки
- log – логирование событий при работе скрипта
- pid – здесь лежит pid процесса для предотвращения одновременного запуска нескольких копий скрипта
- config – основной файл конфигурации скрипта
- networks – список сетей, к которым необходимо строить шейперы
- prefixtree.c – исходник построителя фильтров с хешами
- shaper.php – сам скрипт шейпера
Вся конфигурация скрипта лежит в файле config. Для настройки надо обязательно под себя поменять следующие параметры:
- в начале конфига параметры подключения к БД для забора IP-адресов и параметров скорости
- DEV – интерфейс, на котором строить шейпер
- DIR – направление потока трафика по отношению к абонентам: может быть in или out (входящий и исходящий соответственно)
Остальное менять не нужно.
В файле networks можно описать сети, для которых надо строить шейперы. Если файл пуст – шейперы будут строиться для всех абонентов.
IP-адреса абонентов выбираются из БД в MySQL.
Таблица shapers:
- shaper_id – уникальный идентификатор абонента
- id – идентификатор шейпера
Таблица cl_status:
- ip – IP-адрес абонента
- shaper_id – уникальный идентификатор абонента
- status – состояние абонента (3 – вкл)
- sin – скорость входящая
- sout – скорость исходящая
Скорее всего, проще будет адаптировать запрос выборки IP-адресов абонентов под вашу конкретную БД, чем наоборот. Для этого нужно соответствующим образом поправить запрос в 70-й строке файла shaper.php
Компилирование prefixrtee.c
Для работы скрипта необходимо откомпилировать прилагающийся файл prefixtree.c
Делается это командой: gcc prefixtree.c –o prefixtree
Хочу заметить, что вместе с данным скриптом прилагается слегка исправленный вариант prefixtree, адаптированный для такого использования.
Запуск скрипта
После того как вы внесли соответствующие изменения в config, разобрались с select’ами в shaper.php, откомпилировали prefixtree.c, внесли (если необходимо) нужные сети в networks – можно запускать скрипт.
Запуск должен производиться из-под root, и заключается он просто в:
/usr/bin/php –q shaper.php
После этого скрипт:
- прочитает config
- прочитает networks
- сделает необходимую выборку из БД для каждого IP (на основе networks)
- создаст файл data/_prefixes
- создаст файл data/_speeds
- запустит prefixtree на исполнение, который создаст файл data/_filters
- создаст файл data/_classes
- запустит tc –b data/_classes
В результате чего будет построен и запущен шейпер на заданном интерфейсе по заданным параметрам для заданных IP-адресов.
Если у абонента несколько IP-адресов – будет построен один класс с заданным параметром скорости и все IP-адреса абонента будут направлены в этот класс. Таким образом, если у абонента несколько IP, будет создан один “канал” заданной скорости, который будет делиться между его IP.
Результирующая конфигурация шейпера будет лежать в data/_classes – это готовый файл конфига, который можно скармливать tc с опций batch (-b).
Логи
Все этапы работы скрипта отражаются в логах – папка log.
Статистика
Подобный шейпер успешно обслуживает более 5 тысяч абонентов.
Примечания
Конкретные значения полос пропускания и параметры htb в файле shaper.php необходимо будет править в каждом конкретном случае.
Скачать скрипт
Поскольку кода слишком много, чтобы приводить его здесь целиком, скачать скрипт можно на его домашней странице
Шейпер трафика: режем скорость.
htb.init — это скрипт, который с помощью утилит ip, tc настраивает пропускную способность канала.
Адрес проекта HTB.init http://sourceforge.net/projects/htbinit/
Немного теории:
Шейпер может ограничивать только ИСХОДЯЩИЙ трафик, распределяя его по разным очередям.
Пакеты, не помещающиеся в очередь, отбрасываются. Данные из очереди выдаются на сетевой интерфейс и далее к клиенту.
Каждый конфигурационный файл описывает очередь, это заложено в самом названии файла, который имеет формат:
$HTB_PATH/<ifname>-<clsid>(:<clsid>).<description>
или если «по-русски»:
$HTB_PATH/<Имя интерфейса>-<Номер класса>(:<Номер дочернего класса>).<Комментарий>
clsid — задается цифровыми значениями от 0x2 до 0xFFFF (записывается без приставки 0x)
Сам интерфейс описывается файлом только с именем ifname. Например:
eth0 имеет идентификатор класса clsid=0.
eth0-2 — основной (корневой) класс с clsid=2
eth0-2:3 — класс очереди clsid=3, унаследует ограничения от родительского clsid=2
eth0-2:3:4 — класс очередь clsid=4, унаследует ограничения от родительского clsid=3 и 2, т.е. накладываются еще более жесткие ограничения.
Параметры
— DEFAULT=30 : указывает номер класса, куда попадает трафик не попавший ни под одно правило.
— R2Q=10 : точность шейпера.
— RATE=5Mbit : выделенная (гарантированная) пропускная способность очереди, задается в Kbit, Mbit или bps (bytes per second)
— CEIL=6MBit : максимальная пропускная способность очереди. если не указывать, то по умолчанию CEIL=RATE
— BURST=<bytes> : количество байт без ограничения скорости
— PRIO=<number> : приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет. По умолчанию 0
— LEAF=<параметр> правило распределения внутри самой очереди. default «none». LEAF=sfq — равномерное распределение между участниками очереди.
— RULE= : правило, определяющее трафик, который должен проходить через данную очередь. В одном файле могут присутствовать сразу несколько правил.
RULE=[[source_addr][:port[/mask]],][destination_addr][:port[/mask]]
Если трафик попадает по условиям в очередь -2:10 (например где правило задано по маске), то дальше он уже не будет проверять условия в -2:20 (где допустим будет описано правило с конкретно этим ip), -2:30
— MARK=<метка> : трафик имеющий метку. Например если надо ограничить исходящий трафик от клиента в лок. сети, находящегося за NATом, RULE не прокатит, нужно использовать MARK, и метить нужные пакеты в фаерволе примерно так:
iptables -t mangle -A PREROUTING -s 192.168.0.1 -j MARK –set-mark 101
— TIME : временные параметры. TIME=18:00-06:00;256Kbit
Для корректной работы скрипта, сумма всех RATE дочерних классов (очередей) не должна превышать RATE корневого класса, а значение CEIL в каждой очереди не должно превышать значение в корневом классе.
Установка htb.init
Качаем скрипт htb.init который будет генерировать вам правила шейпера согласно созданным вами файлам конфигурации. Сайт проекта http://sourceforge.net/projects/htbinit/ .
Переименуем покороче скачанный скрипт, назовем например просто htb и поместим в директорию /usr/sbin. Разрешим выполнение этого скрипта:
chmod +x /usr/sbin/htb
По желанию можно добавить скрипт в автозагрузку системы, например добавив в rc.local строку
/usr/sbin/htb start
Теперь надо создать директории и файлы необходимые для правильной работы скрипта.
mkdir /etc/sysconfig
mkdir /etc/sysconfig/htb
touch /var/cache/htb.init
Теперь можно приступать к написанию конфигурационных файлов нашего шейпера.
cd /etc/sysconfig/htb
На сервере имеется локалка на интерфейсе eth0, интернет на eth2. Используется NAT. Скорость интернет-канала 30Мбит\с. Необходимо обеспечить гарантированную скорость доступа по rdp (на сервере проброшены порты к некоторым компам) и ограничить скорость интернет для некоторых компьютеров в сети, при этом не ограничивая скорость в локалке (на сервере еще файлопомойка).
Создаем конфигурационные файлы:
Для входящего трафика:
sudo touch eth0 # Описываем интерфейс eth0
sudo nano eth0
DEFAULT=10 # метка на файл, создаваемый ниже, eth0-2:10.dfl
R2Q=100 # точность ограничений
sudo touch eth0-2.root # корневой класс
sudo nano eth0-2.root
RATE=100Mbit # гарантированная пропускная способность
CEIL=100Mbit # максимальная пропускная способность
BURST=15k # первые 15k без ограничений
sudo touch eth0-2:10.dfl # сюда попадает трафик, не попадающий ни в одно из правил ниже
sudo nano eth0-2:10.dfl
RATE=1024Kbit # гарантированная пропускная способность
CEIL=99Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
sudo touch eth0-2:20.rdp # гарантированный канал для rdp
sudo nano eth0-2:20.rdp
RATE=1Mbit # гарантированная пропускная способность
CEIL=2Mbit # максимальная пропускная способность
BURST=15k # первые 15k без ограничений
LEAF=sfq # равномерное распределение между участниками очереди.
RULE=*:3389, # Применять правило для трафика, у которого исходящий порт — rdp-порт
sudo touch eth0-2:30.87 # ограничиваем скорость для ip 10.10.10.87
sudo nano eth0-2:30.87
RATE=64Kbit # гарантированная пропускная способность
BURST=15k # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=87 # применять правило для пакетов, маркированных меткой 87
Для корректной работы надо добавить правило в фаервол:
sudo iptables -A FORWARD -d 10.10.10.87 -j MARK —set-mark 87
пакеты маркируются в цепочке форвард, поэтому на локалку это правило не действует.
sudo touch eth0-2:31.137 # ограничиваем скорость для ip 10.10.10.137
sudo nano eth0-2:31.137
RATE=64Kbit # гарантированная пропускная способность
BURST=15k # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=137 # применять правило для пакетов, маркированных меткой 137
Для корректной работы надо добавить правило в фаервол:
sudo iptables -A FORWARD -d 10.10.10.137 -j MARK —set-mark 137
Для исходящего трафика:
sudo touch eth2 # Описываем интерфейс eth2
sudo nano eth2
DEFAULT=10 # метка на файл, создаваемый ниже, eth2-2:10.dfl
R2Q=100 # точность ограничений
sudo touch eth2-2.root # корневой класс
sudo nano eth2-2.root
RATE=30Mbit # гарантированная пропускная способность
CEIL=30Mbit # максимальная пропускная способность
BURST=15k # первые 15k без ограничений
sudo touch eth2-2:10.dfl # сюда попадает трафик, не попадающий ни в одно из правил ниже
sudo nano eth2-2:10.dfl
RATE=256Kbit # гарантированная пропускная способность
CEIL=29Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
sudo touch eth2-2:20.rdp # гарантированный канал для rdp
sudo nano eth2-2:20.rdp
RATE=1Mbit # гарантированная пропускная способность
CEIL=2Mbit # максимальная пропускная способность
BURST=15k # первые 15k без ограничений
LEAF=sfq # равномерное распределение между участниками очереди.
RULE=*:3389 # Применять правило для трафика, у которого порт назначения — rdp-порт
sudo touch eth2-2:30.87 # ограничиваем скорость для ip 10.10.10.87
sudo nano eth2-2:30.87
RATE=64Kbit # гарантированная пропускная способность
BURST=15k # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=87 # применять правило для пакетов, маркированных меткой 87
Для корректной работы надо добавить правило в фаервол:
sudo iptables -t mangle -A PREROUTING -s 10.10.10.87 -j MARK —set-mark 87
sudo touch eth2-2:31.137 # ограничиваем скорость для ip 10.10.10.137
sudo nano eth2-2:31.137
RATE=64Kbit # гарантированная пропускная способность
BURST=15k # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=137 # применять правило для пакетов, маркированных меткой 137
Для корректной работы надо добавить правило в фаервол:
sudo iptables -t mangle -A PREROUTING -s 10.10.10.137 -j MARK —set-mark 137
Осталось запустить скрипт:
sudo htb compile # тест. можно посмотреть какие правила будут сформированы и ошибки, если есть.
sudo htb start # запуск
sudo htb stop # остановка
sudo htb restart # перезапуск после внесения изменений в файлы конфигурации
Кто такие шейперы — Look At Me
Одно из самых важных мест в лагере — парк. В этом году строительством парка Домбайского лагеря руководил американец Майкл Виссер.
Все линии готовы, и райдеры начинают потихоньку к ним прикатываться. Майкл достраивает огромный биг-эйр.Вечером нам удалось отловить шейпера Майкла Виссера, который в 10 часов вечера устало заходит в гостиницу и плетется к себе наверх в номер. Согласившись дать интервью, Майкл приглашает в гости.
Рассказывали, что твои приключения в России начались еще в аэропорту, когда ты потерялся
Да, я должен был встретиться с Никитой, который летел из Питера, но его рейс задержали. Я вышел в аэропорт, понял, что меня никто не встречает, а вокруг куча таксистов, кричащих: «Такси! Такси!», — ну, я в итоге подошел к одному и попросил довезти до Шереметьево, откуда у нас был рейс в Минеральные Воды. И там за 15 минут до конца регистрации мы, наконец, встретились с Никитой!
Тут Майкл достает свой I-Pod и начинает записывать видео для своего дневника — как у него берут интервью.
Ты в России в первый раз – как ощущения?
Мне очень нравится! В Америке о России думают как о чем-то суровом и холодном, и я даже прилично волновался перед поездкой, а на самом деле тут оказалось очень здорово и весело!
Вы с Джефом близкие друзья (Джеф был приглашен на Домбай как шейпер Quiksilver-парка в 2008 году – прим. ред.), что он рассказывал тебе про свою поездку на домбайский лагерь?
Он не был многословен, просто сказал: «Чувак! Тебе надо туда поехать! Тебе понравится!». Он мне показал несколько фоток парка, чтобы я поехал сюда в прошлом году, но у меня очень сильно заболел отец, и я поехал к нему, а на Домбай отправился Крис.
Расскажи, как тебе тут работается.
Сейчас очень тяжело, потому что меня некому заменить, и я очень сильно устаю, работая допоздна. Я даже записываю свои часы работы, можешь посмотреть!
Показывает тетрадку с Отпетыми Мошенниками на обложке, в ней ручкой вписаны записи: 8:00-20:00, 8:00-21:00…
Тебе нравится команда шейперов?
Да! Никита – очень крутой. Он для меня тут как гид и переводчик, и он мне очень импонирует. И все ребята-шейперы тоже отличные парни, каждый из них!
Как тебе работается с ребятами?
Я слышу очень много критики в адрес своей работы. У нас в Америке немного другие обычаи – сначала люди говорят тебе комплименты, а потом – критику. Здесь же ситуация кажется немного другой. Тут я слышу только критику.
Должно быть, очень тяжело…
Нет, вовсе нет, я уже привык к критике, проработав много тысяч часов в этом деле. Так что нормально, я привык.
Ты сам уже успел протестировать парк?
В последнее время я поднимаюсь на гору без доски, беру с собой только рюкзак со всякими вещами, и все. Может, дней через 5 мне удастся покататься в парке. Мне кажется, его можно было сделать другим, но проблема в том, что когда я приехал, многое уже было накопано, например, столы про-линии, и я уже ничего не смог с этим сделать.
Что осталось доделать?
Этот здоровый трамплин с пролетом в 37 метров. Это какой-то монстр! Самый большой трамплин, что я когда-либо строил!
Берет I-Pod и с гордостью показывает фотку почти готового кикера на фоне заката.
И какие трюки ты ждешь от райдеров на этом кикере?
Дабл корки!
Как у тебя обстоят дела с общением с местным населением?
Местные люди делятся на две группы: кому я нравлюсь и кому – нет. Одни приветливо улыбаются, здороваются со мной, а другие смотрят на меня хмуро, мол, что этот американец делает здесь? Мне очень нравится местная кухня: хычины, лагманы – все очень вкусно!
Расскажи о вчерашнем случае на горе, когда дул настолько сильный ветер, что весь парк сдуло.
Я был первым, кто поднялся на гору и увидел парк после этого урагана. Если честно, я его просто не узнал! Все было погребено под полутораметровым слоем снега, пусси-лайн вообще не было видно, а все вещи из палатки были раскиданы по всей территории парка. Я просто не поверил своим глазам, когда увидел, где лежала палатка. Как будто ее кто-то взял и просто перенес на огромное расстояние в сторону. Нам понадобился день, чтобы привести все в относительный порядок. Я все записываю на видео, вот!
Показывает видео парка после разрушений, которое он записал на все тот же I-Pod. Зрелище довольно печальное.
Сейчас ты доволен парком?
Да, сейчас следует пообщаться с райдерами, выслушать их мнение по поводу кикеров и сделать необходимые коррективы. А так – парк получился хороший, мне кажется, в нем можно круто поугарать!