Mikrotik QOS в распределенных системах или умные шейперы

А что бы вы со своей стороны могли предложить?
 — Да что тут предлагать… А то пишут, пишут… конгресс, немцы какие-то… Голова пухнет. Взять все, да и поделить.
 — Так я и думал, — воскликнул Филипп Филиппович, шлепнув ладонью по скатерти, — именно так и полагал.
М. Булгаков, «Собачье сердце»

image Про разделение скорости, приоритезацию, работу шейпера и всего остального уже много всего написано и нарисовано. Есть множество статей, мануалов, схем и прочего, в том числе и написанных мной материалов. Но судя по возрастающим потокам писем и сообщений, пересматривая предыдущие материалы, я понял — что часть информации изложена не так подробно как это необходимо, другая часть просто морально устарела и просто путает новичков. На самом деле QOS на микротике не так сложен, как кажется, а кажется он сложным из-за большого количества взаимосвязанных нюансов. Кроме этого можно подчеркнуть, что крайне тяжело освоить данную тему руководствуясь только теорией, только практикой и только прочтением теории и примеров. Основным костылем в этом деле является отсутствие в Mikrotik визуального представления того, что происходит внутри очереди PCQ, а то, что нельзя увидеть и пощупать приходится вообразить. Но воображение у всех развито индивидуально в той или иной степени.

Поэтому я решил написать еще один материал, в котором я смешаю теорию с практикой, визуальными примерами и разобью данный материал на блоки от простого, к сложному. С каждым новым примером я буду добавлять необходимую информацию, и в самом конце вы получите полное представление, как это все работает. Думаю, так будет значительно проще понять основные принципы построения шейпера на микротике.

В данном материале я буду рассматривать только Queue Tree очереди с использованием PCQ. Уж извиняйте, Simple Queues для меня это — несколько не тот уровень возможностей. Так же не будет описан устаревший материал, который применим только для пятых версий ROS, хотя в некоторых моментах я буду на него ссылаться для сравнения.

Начнем с простого примера


Имеем микротик:
WAN интерфейс с белым адресом (1.1.1.1) и входящей скоростью 32 мегабита в секунду
LAN — c подсетью 192.168.0.0/24

Задача нарезать входящую в различных комбинациях (Download) скорость для подсети 192.168.0.0/24. Исходящую скорость (Upload) пока трогать не будем, но отмечу, что ее реализация почти ничем не отличается от реализации входящей скорости.

Для того чтобы что то нарезать на микротике мы должны определится с критериями отбора нужного нам трафика и выделить его. Для этого нам понадобится /ip firewall mangle.

Мангл можно представить в виде своеобразного фильтра, способного отбирать из общего потока пакеты и соединения по определенным критериям и выполнять с ними определенные действия.

Наш единственный критерий известен: нам из общего потока нужны только пакеты, которые идут в подсеть 192.168.0.0/24. В качестве действия с этими пакетами мы выберем — назначение пакету маркировки, впоследствии на основе этой маркировки пакеты можно будет обработать в Queue Tree.

Чтобы правильно промаркировать пакет — нужно знать по каким цепочкам в Mangle он проходит. Для этого нужно знать диаграммы движения пакетов (Packet Flow) причем не абы какие, а именно свежие диаграммы т.к. в шестой версии ROS схема немного изменилась. И естественно, посмотрев на эти диаграммы впервые, у вас на устах ничего кроме матерных слов не будет.

image

Опять же не все так сложно как кажется, данные диаграммы показывают, как ходит трафик во всех случаях, нам же для работы с шейпером понадобится лишь малая их часть.

Исходя из данной диаграммы, можно понять, что интересующий нас трафик идет по пути:

Input Interface > PREROUTING →FORWARD →POSTROUTING → Output Interface

Схема при включенном NAT будет чуть пожирнее:

Input Interface > PREROUTING > DST-NAT >FORWARD > POSTROUTING > SRC-NAT > Output Interface

Какую из цепочек выбрать?

В пятых версиях ROS кроме того где находится NAT, нужно было еще знать где находится обработка очередей global-in, global-out и global-total.
В шестой версии стало все проще, т.к. вышеуказанные обработки упразднили и заменили одним global. И находится этот global в самом конце POSTROUTING, после него обрабатываются очереди SimleQueue и пакет отпускается на волю. Исходя из этого — нам неважно, где он теперь, т.к. все обработки по маркировке производятся до него.

А раз так, то единственное ограничение нам создает только NAT и выбор будет зависеть от направления трафика, который мы хотим промаркировать. По этому случаю накидал свою диаграмму:

image

Как видно из диаграммы, для маркировки полученных пакетов, нам нужны цепочки, в которых доступны серые адреса подсети 192.168.0.0/24 (dst-address).
А видно их только в FORWARD и POSTROUTING.

Для того чтобы промаркировать Upload пакеты нужны цепочки со второй половины диаграммы, в которых доступны серые адреса подсети 192.168.0.0/24 (src-address).
А доступны они во всех трех цепочках PREROUTING, FORWARD, POSTROUTING.

Я рад, что не поленился и написал так много лишних букаф. И все для того, чтобы донести до вас информацию о том, что независимо от направления, которое мы хотим промаркировать, можно выбрать цепочку FORWARD в обоих случаях. Но так нельзя делать в пятых версиях ROS.

С цепочкой определились, теперь нужно определиться с тем, как мы будем помечать пакеты. Сначала пометить соединения, а уже потом в них пометить нужные пакеты? Или просто пометим пакеты и все взлетит?

Как то давно во времена первых версий из шестой линейки, мне написал один хороший человек (за что ему огромное спасибо!), и сказал, что у него в системе интересный глюк. Дал он мне соединение на TeamViewer и показал, как обычная маркировка пакетов помечает на треть (треть! Карл!) пакетов больше, чем маркировка при тех же параметрах, но в пределах соединений. Соответственно и скорости в дереве были в норме, а вот на интерфейсах были на треть выше. Ковырялся долго, ничего не нашел. Делал повторую маркировку по тем же критериям вне коннекшена, предварительно отключив дальнейшие передачи уже помеченных пакетов в вышестоящих правилах. Все это с занесением в лог. Нормальные обычные пакеты, почему они не попали в коннекшен так и не понял.
Поставил ту же версию себе на тестовый стенд (один WAN, один LAN и все это под двойной NAT) настроил правила и поймал тот же глюк у себя. На протяжении четырех-пяти (уже не помню) версий я ловил данный глюк. Потом тупо сделал нагрузочный тест и понял — не такое уж и великое снижение нагрузки на камень, чтобы использовать маркировку в соединениях. С тех пор, на маркировку пакетов в соединениях — я забил. Как руки дойдут — проверю, а пока маркирую пакеты так.

Ну, с этим закончили. Правило в студию!
Данным правилом мы помечаем все пакеты, у которых dst-address равен адрес листу «LAN» ну и назначаем им packet-mark тоже «LAN»

/ip firewall mangle add action=mark-packet chain=forward comment=LAN disabled=no dst-address-list=LAN new-packet-mark=LAN passthrough=yes;

Так же добавим и сам адрес лист:
/ip firewall address-list add address=192.168.0.0/24 disabled=no list=LAN;

На этом маркировка в одном направлении закончена, чтобы промаркировать исходящий трафик, нам нужна копия правила, где dst-address-list=LAN заменен на src-address-list=LAN

Но как я уже писал, для примера мы возьмем только входящий трафик.

Ловим трафик в Queue Tree
Для того чтобы создать очередь PCQ в данном случае требуется одно правило и профиль в Queue Type. Но я создам два правила, чтобы на одном примере показать как в том, или ином случае ведет себя очередь при установке лимитов.

Родительская очередь
/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=30M name=DOWNLOAD parent=global priority=8

Тут стоит прояснить несколько моментов:
parent=global — В данном параметре можно указать либо «global» либо имя интерфейса. Имя интерфейса тут играет роль определенного фильтра направления трафика и используется в сложных конфигурациях для исключения всех направлений кроме указанного интерфейса и действует только для этой очереди и ее потомков. Всегда указывайте в данном параметре «global» эффект будет тот же, а проблем меньше.
max-limit=30M — в условии задачи указано что канал у нас выдает 32 метра, но прописывать нужно чуть меньше доступной скорости. В противном случае вы упретесь в шейпер своего провайдера, ваш же просто не будет работать.

burst-limit=0 burst-threshold=0 burst-time=0s — отключены т.к. их использование мало чего дает при PCQ, но в профиле они имеют достаточную актуальность для использования.

priority=8 — приоритет очереди, 1 — высший приоритет, 8 — низший приоритет. НЕ РАБОТАЕТ если очередь имеет потомков.

Приоритеты работают только у потомков, причем конкурируют они друг с другом не только в пределах своего родителя, но и с потомками других родителей и только в случае общего дедушки, который лимитирует этим дармоедам скорость. При одинаковых приоритетах они распределят между собой всю доступную дедушкой скорость. При разных — сначала из общей дедушкиной миски едят высокоприоритетные, потом едят те у кого приоритет пониже и то только если что-то осталось, ну или родители развели дедушку на Limit-at. Хотя и родители могут устроить битву титанов среди своих потомков, если у них установлен не только Limit-at, но и Max-limit. Это будет в стиле: «не сжирайте все, у деда есть и другие дети с внуками от первого брака!»
Ну да постебались и хватит! Про лимиты и приоритеты расскажу более наглядно чуть позже.

В общем, мы создали родителя, теперь ему нужен потомок. Но для добавления потомка (конечной очереди) сначала необходимо добавить профиль. Добавляем.

/queue type add kind=pcq name= PCQ_DOWNLOAD_LAN pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=0 pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

kind=pcq — Указываем что очередь которая использует данный профиль является инициатором подочередей PCQ
pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s — Настройки Burst Скоростей, об этом чуть позже.
pcq-classifier=dst-address — Данный параметр указывает по какому классификатору будут создаваться PCQ очереди. В данном случае по адресу назначения (входящий трафик)

pcq-dst-address-mask=32 и pcq-src-address-mask=32 — задают количество адресов в одной очереди. (32=одна очередь на один ip адрес)

pcq-rate=0 — Устанавливает верхний лимит скорости для одной PCQ очереди (в нашем случае для одного ip адреса) Если указан ноль — скорость не ограничена и будет разделена поровну между очередями (ip адресами). В нашем случае 30 мегабит будут разделены поровну между активными очередями (ip адресами).

pcq-limit=50 — лимит размера одной очереди (для одного ip адреса) Все данные в этой очереди при достижении лимитов задерживаются, все что в нее не влезло — уничтожается.

pcq-total-limit=2000 — лимит размера всех очередей.

Теперь, когда у нас есть родительская очередь и профиль под потомка, мы добавим самого потомка:

/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name=LAN packet-mark=LAN parent=DOWNLOAD priority=8 queue=PCQ_DOWNLOAD_LAN;

packet-mark=LAN — вот тут мы ловим в очередь поток промаркированных в мангле пакетов.
parent=DOWNLOAD — указали родителя, который ограничил нам скорость.
queue=PCQ_DOWNLOAD_LAN — ссылаемся на профиль с настройками в Queue Type

Ну, вот и закончили с правилами. Посмотрим на визуальную диаграмму.

Все что происходит наверху, вы уже знаете, далее смешанные промаркированные пакеты в хаотичном порядке, кучей подхватываются очередью потомком. И тут начинается самое интересное.

image

Допустим, у нас сейчас в подсети работают три машины: 192.168.0.1, 192.168.0.2 и 192.168.0.3.

В связи с тем, что потомок привязан к профилю с именем «PCQ_DOWNLOAD_LAN», профиль ему сообщил: что нужно создать под каждый встреченный в промаркированном потоке dst-ip адрес отдельную PCQ очередь.

У нас внутри Queue Tree очереди будет создано три PCQ очереди (потока) с одинаковыми параметрами pcq-rate, pcq-limit и настройками Burst скоростей.

В данном случае очередь сработала как своеобразный сортировщик пакетов. И для каждого пользователя создала индивидуальную очередь.

Каждая очередь проходит через pcq-rate, именно эта штука и задерживает пакеты в индивидуальных очередях.

Далее пакеты смешиваются и поступают во вторую часть Queue Tree очереди c именем «LAN», где проходят проверку на суммарную скорость по Max-Limit, если он есть и исчерпан, то этот Max-limit будет поделен поровну между PCQ-очередями (потоками), задержка производится на уровне pcq-rate, какие-то очереди ускоряются, какие-то притормаживаются. Все что не влезло в pcq-limit — уничтожается.

Но у нас этого параметра в очереди «LAN» не установлено и поэтому трафик ползет вверх к родительской очереди (DOWNLOAD). Там все происходит по аналогии, проверяется Max-Limit и если он достигнут — родительская очередь пинает pcq-rate на закрытие дышла. Скорости потоков выравниваются, и все приходит в норму.
Представим на секунду, что мы не установили Max-Limit в родительской очереди. Так вот, если нигде по пути трафика при pcq-rate=0 не было обнаружено значения Max-Limit, то и вся очередь не будет работать, весь трафик пройдет сквозь шейпер без задержек, т.к. некому сообщить pcq-rate что канал не резиновый.

Многих мучает вопрос, если в данном случае pcq-rate=0, пользователей три, двое спят, а один качает. Он выжирает все 30 мегабит? — Да!

А что будет, если проснется еще один и тоже начнет качать? — Будет произведено перестроение и выравнивание скоростей. 30 мегабит они поделят поровну. Единственный нюанс — на это требуется время, второй пользователь будет немного медленнее набирать скорость, чем обычно.

Суть механизма заключается в задержке и уничтожении пакетов, которые не влезли в лимит. Протокол TCP устроен таким образом, что в рамках соединения — сервер который отправляет данные клиенту, проверяет как они дошли до него, если у пакетов выросла задержка или пакет потерялся (нарушение последовательности) сервер снижает скорость отправки чтобы увеличить стабильность.

pcq-limit и pcq-total-limit задаются экспериментально, чем больше лимит — тем больше задержка и больше занято оперативной памяти роутера. Чем меньше лимит — тем больше пакетов будет уничтожено.

Что будет, если задать pcq-rate=5M?
Каждый пользователь получит не более 5 мегабит. 3 активных пользователя * 5 мегабит =15 мегабит.

Три активных пользователя, все качают по полной, pcq-rate=11M?
Скорость упрется в Max-limit родительской очереди (30M) и данная скорость будет поделена между пользователями равномерно по 10 мегабит. Если один из них уйдет с закачки или снизит свою скорость минимум до 8 мегабит, двое остальных разгонятся до 11 мегабит.

Я очень надеюсь, что по данному примеру все понятно, если непонятно — прочтите еще раз и еще раз, далее будет сложнее.

Burst


Технология Burst предназначена для подачи увеличенной скорости при назначенном лимите на короткое время. Использовать данную функцию целесообразно на небольших по скорости тарифах, для ускорения веб-серфинга или быстрой подгрузки данных в приложения. Данная функция работает только в случае если pcq-rate не равен нулю.
Не буду до посинения грузить вас графиками и формулами расчета, лучше накидаю пример.
Pcq-rate=2M
pcq-burst-rate=4M
pcq-burst-threshold=1M
pcq-burst-time=10s

Максимальная скорость работы пользователя равна 2 мегабитам. Если скорость его работы в данный момент менее 1 мегабита (pcq-burst-threshold), ему станет доступна скорость в 4 мегабита (pcq-burst-rate) на 10 секунд (на практике меньше) это pcq-burst-time. Счетчик начинает тикать с того момента как будет превышен порог в 1 мегабит (pcq-burst-threshold), по истечении времени скорость упадет до pcq-rate, чтобы Burst снова стал доступен — скорость пользователя должна упасть ниже 1 мегабита и находится там не менее 10 секунд (pcq-burst-time)

Понятно, что это очень грубое объяснение, на самом деле время доступности burst рассчитывается по непростому алгоритму — время делится на 16 отрезков и учитывая почти все переменные скорости и лимитов рассчитывается время действия.
Данная функция потребляет значительное количество ресурсов, используйте ее с умом.

Для справки: При внесении любых изменений, в любую очередь и в любом ее проявлении (Tree или Simple) — все счетчики обнуляются в т.ч. и счетчики Burst. Если вы используете скрипты для автоматической коррекции значений Max-Limit типа QOSEvxController — будьте готовы отказаться от Burst или использовать циклы проверки очередей в QOSEvxController не так часто.

Ведро с болтами (Bucket)


Так же с недавнего времени в шестой версии ROS для очередей появился новый параметр bucket-size (размер ведра). Данный параметр может быть изменен в пределах от 0.1 до 10 и используется для задания емкости ведра с токенами. Емкость ведра рассчитывается по форумуле:
Емкость в МЕГАБАЙТАХ=bucket-size * max-limit
Над каждой очередью нависает ведро с гомном токенами, пока трафик в данной очереди не превышает лимит (max-limit) токены накапливаются в данном ведре. При переполнении ведра токен падающий в полное ведро уничтожается.

На что тратятся токены.

/queue tree add name=download parent=global packet-mark=PC1-traffic max-limit=10M bucket-size=10;

В данном примере, емкость ведра будет равна: (max-limit=10M) * (bucket-size=10) = 100 мегаБАЙТАМ
Если пользователь или пользователи потока пакетов с маркировкой «PC1-traffic» до недавнего времени ничего не качали на полной скорости — ведро с токенами в данной очереди будет полным, а это целых сто мегабайт трафика. И вот решили они дружно, что то качнуть, так вот, первых 100 мегабайт трафика они получат без ограничения скорости по max-limit, когда 100 мегабайт будет скачано очередь начнет ограничивать скорость согласно заданному max-limit=10M.

Кроме этого, если у очереди есть родитель с более жирным max-limit, то после того как потомок выжрет все свои токены, из своего ведра, он начнет забирать токены у родительской очереди.

Для чего это нужно?
Bucket-size это как своеобразный Burst, только не по скорости, а по объему трафика. Применение его совместно с PCQ очередями даст лишь сомнительную пользу. В одиночных сеялках типа pfifo, red и sfq может быть крайне полезен. Для PCQ очередей — единственное, что приходит в голову, это то, что мы лимитируем родительскими очередями скорость, которая чуть ниже реальной скорости канала. Грамотное использование данной функции может кратковременно более полно эксплуатировать всю доступную скорость канала и сглаживать пики активности пользователей.

Более подробная диаграмма работы ведра:

image

Эквиваленты маркировки трафика


В данном примере я указал, что у нас одна подсеть (192.168.0.0/24) с тремя пользователями (192.168.0.1, 192.168.0.2, 192.168.0.3). Мы пометили трафик к данным адресам одним правилом в mangle и одним адрес-листом.
На всякий случай скажу, что для mangle нет разницы, как мы ему скормим адреса для пометки — обработаны они будут одинаково.

Подсеть целиком:
/ip firewall address-list add address=192.168.0.0/24 disabled=no list=LAN;

Диапазон адресов:
/ip firewall address-list add address=192.168.0.1-192.168.0.3 disabled=no list=LAN;

Отдельные адреса:
/ip firewall address-list add address=192.168.0.1 disabled=no list=LAN;

/ip firewall address-list add address=192.168.0.2 disabled=no list=LAN;

/ip firewall address-list add address=192.168.0.3 disabled=no list=LAN;

Аналогично обстоит дело и с PCQ очередями. PCQ очередь без проблем разбирает один поток пакетов, помеченный одним правилом, состоящий из адресов разных подсетей на подочереди.

Допустим, что мы подмешали еще трех пользователей из другой подсети (192.168.1.1, 192.168.1.2, 192.168.1.3). Просто добавив нужные записи в адрес-лист. Тогда получим такую картину:

image

Исходя из всего вышеперечисленного, можно сделать вывод, что оперируем мы не подсетями, а группами ip адресов, которые создаем с помощью адрес-листов

В данном случае нет смысла раздельно маркировать трафик, делать два профиля и две очереди.
Такой подход необходим только в следующих случаях:

Когда требуется задать индивидуальный Max-Limit для выбранной группы адресов.
Когда требуется различный приоритет для групп адресов или типа трафика.
Когда требуется реализация различных тарифных планов для группы адресов. (pcq-rate)
И во всех возможных комбинациях вышеперечисленных случаев.

А вот пример того, как делать не надо:

image

Полный листинг примера:

/ip firewall mangle add action=mark-packet chain=forward comment=LAN disabled=no dst-address-list=LAN new-packet-mark=LAN passthrough=yes;

/ip firewall address-list add address=192.168.0.0/24 disabled=no list=LAN;

/queue type add kind=pcq name= PCQ_DOWNLOAD_LAN pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=0 pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=30M name=DOWNLOAD parent=global priority=8;

/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name=LAN packet-mark=LAN parent=DOWNLOAD priority=8 queue=PCQ_DOWNLOAD_LAN;

Пример второй. Приоритет одних, над другими.


Допустим, что мы администратор организации с небольшим количеством сотрудников.

Имеем исходные данные:

WAN интерфейс с белым адресом (1.1.1.1) и входящей скоростью 32 мегабита в секунду
LAN — c подсетью 192.168.0.0/24 (Рабочие станции Директоров)
LAN2 — c подсетью 192.168.1.0/24 (Рабочие станции Менеджеров)

В данном примере мы как раз, имеем один канал и две группы потребителей с разными приоритетами. Где директора имеют приоритет над менеджерами. Именно в этом случае для реализации данной схемы потребуется раздельная маркировка пакетов и раздельные очереди для групп пользователей.

Правила для маркировки:
/ip firewall mangle add action=mark-packet chain=forward comment=GROUP-A_DW disabled=no dst-address-list= GROUP-A new-packet-mark= GROUP-A_DW passthrough=yes;

/ip firewall mangle add action=mark-packet chain=forward comment=GROUP-B_DW disabled=no dst-address-list= GROUP-B new-packet-mark= GROUP-B_DW passthrough=yes;

Два правила для маркировки трафика с разными packet-mark и два списка для присвоения адресам принадлежности к группам.

/ip firewall address-list add address=192.168.0.0/24 disabled=no list=GROUP-A;
/ip firewall address-list add address=192.168.1.0/24 disabled=no list=GROUP-B;

Пришло время создать профили PCQ для очередей.
Сколько нужно профилей? По идее на загрузку хватит и одного профиля, но я всегда создаю по отдельному профилю на каждую группу и на каждое направление. Это позволяет иметь гибкие настройки на будущее, без дополнительного вмешательства в уже созданные правила и очереди

/queue type add kind=pcq name= GROUP-A_DW pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=0 pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

/queue type add kind=pcq name= GROUP-B_DW pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=0 pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

Создаем дерево очередей:

Родительская очередь:
/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=30M name=DOWNLOAD parent=global priority=8;

Потомки:
/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name= GROUP-A_DW packet-mark= GROUP-A_DW parent=DOWNLOAD priority=7 queue= GROUP-A_DW;

/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name= GROUP-B_DW packet-mark= GROUP-B_DW parent=DOWNLOAD priority=8 queue= GROUP-B_DW;

В данном примере нет ничего сложного, разница между очередями лишь в разных маркировках пакетов и разных приоритетах.

При низких скоростях данная схема будет прозрачно пропускать трафик через себя и любой из потребителей может получить все 30М указанных в родительской очереди.

При нехватке скорости в родительской очереди скорость начнет перераспределяться между потребителями по следующей схеме:

Группа с адресами GROUP-A_DW имеет более высокий приоритет (priority=7), ей будет отдана вся скорость родительской очереди (30M) и равномерно разделена между активными потребителями в пределах этой очереди.

Если данная группа не утилизировала весь доступный лимит скорости (30М), остатки этого лимита будут переданы в очередь с более низким приоритетом GROUP-B_DW (priority=8), где данные остатки будут равномерно разделены между активными потребителями в пределах этой очереди.

Если группа GROUP-A_DW утилизировала весь доступный лимит в 30 мегабит, группа GROUP-B_DW не получит вообще никакой скорости и никакой возможности передавать и получать пакеты из сети.

Для того чтобы группе с низким приоритетом оставалось хотя бы некоторое количество скорости, можно задать в очереди параметр limit-at=5M. Но данный параметр можно задать только совместно с параметром Max-Limit, ограничивать максимальную скорость группы нам не требуется — поэтому просто скопируем его из родительской очереди.

И вторая очередь после правок будет выглядеть так:
/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=5M max-limit=30M name=GROUP-B_DW packet-mark=GROUP-B_DW parent=DOWNLOAD priority=8 queue=GROUP-B_DW;

В таком случае при нехватке скорости в родительской очереди, очередь с низким приоритетом будет всегда получать минимум 5 мегабит, которые сможет равномерно разделить между активными потребителями в пределах этой очереди.

Пример третий. Реализация тарифных планов с разделением на группы с разными приоритетами


В данном примере будет рассмотрен своеобразный гибрид, который включает реализации из первых двух примеров.

Предположим, что мы субпровайдер с ограниченными финансовыми и техническими возможностями. У нас есть узкий канал в интернет, пара тарифных планов и две категории абонентов (физ.лица и юр.лица). Чаще всего, при предоставлении услуг юридическим лицам мы получаем от них большую выгоду, чем от физических лиц на тех же показателях скорости. Вместе с этим, мы предоставляем юридическим лицам некоторые дополнительные гарантии в виде гарантированной скорости и более оперативной технической поддержки.

Ну и как чаще всего бывает — мы немного увлеклись и подключили чуть больше абонентов, чем может вытянуть наш канал в интернет. По правильному — нужно расширить канал или подключить дополнительный с последующей балансировкой нагрузки. Но как уже было сказано, на это пока нет возможностей.

Но скорости в прайм-тайм не хватает, юридические лица начинают звонить и жаловаться на несоответствующую тарифному плану скорость, задержки пакетов, заикания телефонии и пр.

Частично облегчить данную ситуацию поможет шейпер с приоритетами как во втором примере, единственные отличия в том, что в данном примере скорость на одного абонента строго лимитирована и присутствует несколько тарифных планов.

Так же как и в предыдущих примерах, мы рассмотрим только входящую скорость. Однако во избежание путаницы в комментариях, именах маркировок и именах очередей будет присутствовать upload скорость.

Сокращения:
FIZ — физическое лицо.
UR — юридическое лицо.
1024K-1024K — Скорости по тарифу: Download-Upload
DW- Download
UL — Upload

Маркировка пакетов:

/ip firewall mangle add action=mark-packet chain=forward comment=FIZ_1024K-1024K_DW disabled=no dst-address-list= FIZ_1024K-1024K new-packet-mark= FIZ_1024K-1024K_DW passthrough=yes;

/ip firewall mangle add action=mark-packet chain=forward comment=FIZ_3072K-3072K_DW disabled=no dst-address-list= FIZ_3072K-3072K new-packet-mark= FIZ_3072K-3072K_DW passthrough=yes;

/ip firewall mangle add action=mark-packet chain=forward comment=UR_1024K-1024K_DW disabled=no dst-address-list= UR_1024K-1024K new-packet-mark= UR_1024K-1024K_DW passthrough=yes;

/ip firewall mangle add action=mark-packet chain=forward comment=UR_3072K-3072K_DW disabled=no dst-address-list= UR_3072K-3072K new-packet-mark= UR_3072K-3072K_DW passthrough=yes;

Четыре правила маркировки, которые выдадут нам четыре потока помеченных пакетов, рассортированных по четырем тарифным планам (Два для физ.лиц и два для юр.лиц.)

Чтобы привязать абонента к определенному тарифному плану, нужно поместить его ip адрес в нужный адрес-лист:

/ip firewall address-list add address=192.168.0.1 disabled=no list= FIZ_1024K-1024K;
/ip firewall address-list add address=192.168.0.2 disabled=no list= FIZ_3072K-3072K;
/ip firewall address-list add address=192.168.0.3 disabled=no list= FIZ_3072K-3072K;
/ip firewall address-list add address=192.168.0.4 disabled=no list= UR_3072K-3072K;
/ip firewall address-list add address=192.168.0.5 disabled=no list= UR_3072K-3072K;

И т.д.

Теперь необходимо добавить необходимые профили для очередей:

/queue type add kind=pcq name= FIZ_1024K-1024K_DW pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=1M pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

/queue type add kind=pcq name= FIZ_3072K-3072K_DW pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=3M pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

/queue type add kind=pcq name= UR_1024K-1024K_DW pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=1M pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

/queue type add kind=pcq name= UR_3072K-3072K_DW pcq-burst-rate=0 pcq-burst-threshold=0 pcq-burst-time=10s pcq-classifier=dst-address pcq-dst-address-mask=32 pcq-dst-address6-mask=64 pcq-limit=50 pcq-rate=3M pcq-src-address-mask=32 pcq-src-address6-mask=64 pcq-total-limit=2000;

Опять же я создал четыре профиля вместо двух, для сохранения гибкости настроек на будущее.

Далее построим дерево очередей:

Родительская очередь:
/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=30M name=DOWNLOAD parent=global priority=8

Потомки:
/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name=FIZ_1024K-1024K_DW packet-mark=FIZ_1024K-1024K_DW parent=DOWNLOAD priority=8 queue= FIZ_1024K-1024K_DW;

/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name=FIZ_3072K-3072K_DW packet-mark=FIZ_3072K-3072K_DW parent=DOWNLOAD priority=8 queue= FIZ_3072K-3072K_DW;

/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name=UR_1024K-1024K_DW packet-mark=UR_1024K-1024K_DW parent=DOWNLOAD priority=7 queue= UR_1024K-1024K_DW;

/queue tree add burst-limit=0 burst-threshold=0 burst-time=0s disabled=no limit-at=0 max-limit=0 name=UR_3072K-3072K_DW packet-mark=UR_3072K-3072K_DW parent=DOWNLOAD priority=7 queue= UR_3072K-3072K_DW;

При реализации данного примера все будет работать следующим образом:

При низких скоростях абоненты без проблем получают свою тарифную скорость, которая ограничена параметром pcq-rate. Но самое интересное, начинается, когда активных абонентов больше чем может выдать канал.

Родительская очередь ограничена 30 мегабитами.

Тарифные планы физических лиц и сами физические лица между собой равноправны.
Тарифные планы юридических лиц и сами юридические лица тоже между собой равноправны.
Но в связи с тем, что очередь юридических лиц имеет более высокий приоритет, отсюда следует, что и сами юридические лица с их тарифными планами тоже имеют более высокий приоритет — и они будут обрабатываться первыми.

Вся доступная скорость отдается в тарифы для юридических лиц, каждый такой абонент ограничен скоростью тарифа заданной в параметре pcq-rate. Тем не менее, если данные абоненты интенсивно работают и их потребление трафика превышает в сумме 30 мегабит, то получим такую картину:
30 мегабит будут разделены поровну между юридическими лицами, на основании текущего количества пакетов в каждой PCQ очереди. На самом деле объяснить данную ситуацию не так просто, но я попробую.
Предположим, что у нас все перечисленные юридические лица качают «по полной». В данный момент есть четыре абонента с тарифом в 1 мегабит и двенадцать абонентов с тарифом в 3 мегабита.

4×1М = 4 мегабита
12×3M = 36 мегабит
4М + 36М = 40 мегабит требуется абонентам с одинаковым приоритетом.

Но у нас всего 30 мегабит. Все бы было просто в случае одинаковых тарифных планов: 30 мегабит поровну поделились бы между абонентами и все. Но как будет распределена скорость, если тарифы у нас разные в пределах одной приоритетной группы.

Как распределится недостаток скорости?
В голову приходит два варианта развития событий, но лишь один из них верный.

Недостаток скорости будет распределен в процентном соотношении исходя из скорости тарифного плана. Примерно как то так:

(100% / 40 мегабит которые требуются) = 2.5
30 мегабит которые есть * 2.5 = 75% от того что требуется мы имеем.

(1 мегабит / 100%) * 75% = 0.75 мегабита
(3 мегабита / 100%) * 75% = 2.25 мегабита

Проверяем:
4 абонента с тарифом в 1М (4×0.75) = 3 мегабита.
12 абонентов с тарифом в 3М (12×2.25) = 27 мегабит.
27+3 = 30 мегабит.

В принципе логично и относительно честно, только вот к сожалению данный сценарий будет обработан несколько иначе, а именно:
Вся доступная скорость (30 мегабит) будет распределятся равномерно, между участниками в равные единицы времени.
Представьте чан с 30 литрами воды, из которого отходят трубки одинакового сечения и N- количество стаканов разных размеров на столе, в которые одновременно разливают ограниченный объем воды одинаковыми струйками. В нашем примере самый маленький стакан имеет объем один литр, стакан побольше — три литра. (Три литра! Карл!) Как только мелкие стаканы будут наполнены — в них перестают лить воду. Вся оставшаяся вода будет продолжать разливаться в более крупные стаканы. Если и после этого вода в чане останется — она будет разлита в стаканы на другом низкоприоритетном столе. Но воды, то у нас не хватает даже на один стол.

Сложные вычисления:

Первый этап, первый временной промежуток:
4 стакана по литру = 4 литра
12 стаканов по три литра, но данном промежутке времени в них залит только литр = 12 литров.

30 литров — (4+12) =14 литров воды осталось в чане.

Второй этап, второй временной промежуток:
В связи с тем, что стаканов более трех литров в примере нет — просто разделим остатки воды между трехлитровыми стаканами.
14 литров / 12 стаканов= 1,1666666666666666666666666666667

Итог вычислений:
Пользователь на тарифе 1 мегабит получит весь мегабит целиком.
Пользователь на тарифе 3 мегабита получит 1+ 1,16 = 2,16 мегабита

Тоже самое если использовать простые вычисления:
(30 литров — 1 литр * 4) / 12 =2,16

Если внимательно посмотреть на оба примера (неправильный и верный) можно увидеть что в первом примере общая нехватка скорости по тарифу у всех ровно четверть от заявленной скорости и пострадали все тарифы одинаково. Во втором случае мелкие тарифные планы не почувствовали нехватки и получили заявленную скорость, однако тарифы с более высокой скоростью ощутили нехватку почти на треть.

Исходя из излишне-изложенной и не самой удачной метафоры, можно условно сказать, что тарифы с низкими скоростями имеют некий приоритет над тарифами с более высокими скоростями, при нехватке скорости, даже с одинаковым приоритетом.

Да это не со

© Habrahabr.ru