Thursday, October 19, 2006

Thoughts on HFSC

Реших да напиша стятия за PF ама то като гледам с каква скорост се развивата няма да стане скоро. Затова ще опитам да си разясня HFCS планировчика. Ще поясня основните неща, оптимизацията и "хватките" са си ваше дело.

Откъде идва името HFSC? Това е съкращение на Hierarchical Fair Service Curve Algorithm. Ето и каква е идеята. Добре е планировчика да се самонаглася и да взема рашения според случая - selfadopted.
В HFSC има ДВА планировчика(packet schedularas). Първия е гарантирания или т.н. realtime, а втория linkshare. HFSC ще избере автоматично, коj от двата ще използва ako на места параметрите се препокриват. Параметрите, които контролират тези два планировчика са:

realtime - той контролира минималната ширина (bandwidth), която се изисква от опашката. Когато има възможност HFSC предпочита този, той е default. Големината му ще нараства докато се достигне лимита на канала или се достигне upperlimit ограничението. Ако нямаме realtime планировчик или "интернета" ни е малко и не можем да гарантираме нужния минимум, ще се използва linkshare. Този параметър e опционален.

Още по нагледно:


if (there is an eligible packet)
/* real-time criteria */
send eligible packet with min. deadline d ;
else
/* link-sharing criteria */
send packet with min. virtual time v ;


linkshare - той определя колко да се вземе трафика за текущата от опашката баща (parent queue). Разпределя пропорционално интернета. Ако имаме излишък той ще се използва според допълнителните параметри или докато се достигне upperlimit (ako e упоменат). И този параметър е опционален.

Mалко по особено е. Където са дефинирани realtime и linkshare и параметрите в тях се препокриват ще се предпочете realtime. Realtime е планировчика по подразбиране. И още нещо, ако в дефиницията на опашката (а не в altq) не се използва linkshare задължително трябва да се напише bandwidth! В противен случай pfctl ще се оплаче. Запомнете го, макар май се промени това в новите версии на pf.

Надлежно показвам какво съм видял в кода:

ls - linkshare
rt - realtime
ul - upper limit

/* if link_share is not specified, use bandwidth */
if (opts->lssc_m2 == 0)
opts->lssc_m2 = pa->bandwidth;

if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) ||
(opts->lssc_m1 > 0 && opts->lssc_m2 == 0) ||
(opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) {

warnx("m2 is zero for %s", pa->qname);
return (-1);
}

Пример:

altq on $ext_if hfsc bandwidth 45Mb
queue{dns, ssh, www, mail, other}
queue dns bandwidth 10%
queue ssh bandwidth 10%
queue mail bandwidth 20%
queue www bandwidth 40%
queue other hfsc(default)


upperlimit - това е максималното количество "интернет", което някоя от опашките може да използва. И още нещо, което се разбира ама аз да си го кажа: Стойността на upperlimmit трябва да е по-голяма от лимитите поставени в realtime и linkshare. Този параметър е опционален.

Нуждаем се и от малко теория. Ето и необходимата порция.
След всеки един от тези параметри има число, което указва каква част от интернет потока трябва да се задели или от следните 3 числа (m1 d m2). Какво заначат тези числа

m1 - първоначалното количество интернет.
d - забавянето (time delay, in milliseconds)
m2 - корекция на количеството интернет

Тези параметри определят така наречената "сервизна крива" (service curve). Tя може да бъде два типа:
изпъкнала (convex) при m1 > m2
вдлъбната (concave) при m1 < m2.

ВАЖНО:
1) realtime параметрите не могат да бъдат по-големи от 75% от целия ни интернет (total interface bandwidth)
2) кривата на realtime трябва да е винаги изпъкнала (m1 > m2).

Да онагледим нещата:

# PARENT QUEUE DEFINITION
altq on $ext_if hfsc bandwidth 45Mb
queue{dmznet, prvnet, others}

# CHILD QUEUE DEFINITIONS
# ако пакетите се задържат до 10 сек. ще вземе 50% или повече
# от цялия интернет. Когато пакетите пристигат повече и повече и
# планировчика ги задържа повече от 10 сек. ще се опита да се коригира
# и завземе 65% от интернета.
queue dmznet hfsc(linkshare (50% 10000 65%))

# и тук е същото, само че ще се коригира към по-малко!
queue prvnet hfsc(linkshare (40% 5000 25%))
queue others hfsc(default)


Нека да поясним нещата. Може да разглеждате опашките като скачени съдове, едното е за сметка на другото. Затова сумата от параметрите от един вид не трябва да надвишават количеството интернет (total bandwith) като default опашката не влиза в тия сметки. Тези стойности могат да са %, b, Kb, Mb, Gb.

Да направим анализ. Да кажем, че в DMZ зоната има FTP сървър и в един момент почва да бълва трафик и "тръбата" от 50% не може да смогне (бави пакетите повече от 10 сек.) затова планировчика я разширява автоматично. Разширяването е за сметка обаче на privnet. Защо съм сложил съм 5 сек? Расъждавам така, ако някое типче тръгне да сваля нещо ще запълни "тръбата" и аз ще го резна като изрично намаля капациета. Второ, ако забавянето е повече от 5 сек. то някъде другаде(в случая dmz зоната) става нещо, трябва повече интернет. Хм, за оптимизацията се разбрахме не мога да кажа точно какво трябва да е забавянето (delay).
Запамети. Горната граница на разширяването може да се ограничи единствено от upperlimit.

Нещата стават още по-интересни, когато намесим и realtime. Kакто ви казах могат да бъдат дефинирани едновременно. HFSC автоматично ще избере, кои ще свърши по-добра работа. Може да изберете да имат еднакви параметри, може и да измислите нещо по-хитро. Дерзайте, но не забравяйте, че сервизната крива на realtime винаги трябва да бъде изпъкнала (m1 > m2). И от тук и простичкото правило: ако искате при забавяне да увеличите канала - linkshare, ako не - realtime.

Пример:

# PARENT QUEUE DEFINITION
altq on $ext_if hfsc bandwidth 45Mb
queue{dmznet, prvnet, others}

# CHILD QUEUE DEFINITIONS
queue dmznet hfsc(linkshare (50% 10000 65%))

# HFSC ще избере сам.
queue prvnet hfsc(realtime (40% 5000 25%) linkshare (40% 5000 25%))
queue others hfsc(default)

И остана последно смятането на количествата интернет. Сравнете следните два примера:

# CBQ
altq on $ext_if cbq bandwidth 20Mb queue{dmznet, prvnet, others}

# prvnet gets 8Mb
queue prvnet bandwidth 40% queue{host1, host2}
# host1 gets 4Mb
queue host1 bandwidth 50%

# host2 gets 4Mb
queue host2 bandwidth 50%

# HFSC
altq on $ext_if hfsc bandwidth 20Mb queue{dmznet, prvnet, others}

# prvnet gets 8Mb
queue prvnet hfsc(linkshare 40%) queue{host1, host2}
# host1 gets 4Mb
queue host1 hfsc(linkshare 20%)

# host2 gets 4Mb
queue host2 hfsc(linkshare 20%)


Какво се забелязва? CBQ разпределя параметрите спрямо parent опашката, а HFSC спрямо root! Много често се греши внимавайте!

Искам да спомена и един друг параметър, който често пипам qlimit. Той определя колко да е голяма опашката и от там колко гладко да се обработва. По подразбиране е 50 пакета. Преди да правите радикални промени поиграйте си с qlimit.

queue oRel bandwidth 128Kb qlimit 100 hfsc( linkshare 128Kb ) { oRelTCP, oRelUDP }
queue oRelTCP bandwidth 64Kb qlimit 60 hfsc( linkshare 64Kb default red )
queue oRelUDP bandwidth 64Kb qlimit 60 hfsc( linkshare 64Kb)


Какво да използваме? Ако искаме да сортираме трафика по приоритет ще се възползваме от PRIQ. Ако искаме да разпределим нещата "на калпак" - CBQ. И накрая ако искаме всичко това плюс разни други красиви добавки HFSC.

No comments:

algorithms (1) cpp (3) cv (1) daily (4) emacs (2) freebsd (4) java (3) javascript (1) JSON (1) linux (2) Lisp (7) misc (8) programming (16) Python (4) SICP (1) source control (4) sql (1) думи (8)