Мы хотели эту тему раскрыть на надвигающемся HighLoad, но не сложилось. Зато, сложились другие наши доклады, а этот, в связи с поступающими вопросами по теме, я расскажу тут.
На одном из наших проектов мы отдаем большое количество видео контента. Наши сервера отдают около 8 ГБит/сек, среди этого html/css/js контент занимает около 300-400 Мбит.
Отдающие сервера можно поделить на 2 части: медиа-сервера, которые отдают видео и картинки и www-сервера, которые отдают вышеупомянутый html/css/js.
Медиа-сервера специфичны тем, что у них трафик, как правило, держится на 1Гбит, 100kpps, т.е. они отдают полный интерфейс. У них относительно маленькое количество tcp-сессий, и в рамках одной сессии выдается большой объем.
# netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c
3 CLOSE_WAIT
1 CLOSING
2630 ESTABLISHED
67 FIN_WAIT1
1491 FIN_WAIT2
1 LAST_ACK
7 LISTEN
50 SYN_RECV
9246 TIME_WAIT
На www-серверах tcp-сессии менее долгоживущие и их гораздо больше. Отдается 150-200 Мбит, 30kpps.
# netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c
77 CLOSE_WAIT
63 CLOSING
12393 ESTABLISHED
586 FIN_WAIT1
194 FIN_WAIT2
82 LAST_ACK
9 LISTEN
2038 SYN_RECV
323 SYN_SENT
149863 TIME_WAIT
И там и там включены net.ipv4.tcp_tw_reuse и net.ipv4.tcp_tw_recycle, используется CentOS, стандартное ядро, стандартные драйвера. Машины Intel-ы Xeon-ы 1 или 2х процессорные, многоядерные. Сетевые карты встроенные, Intel Corporation 82573L и Broadcom Corporation NetXtreme II BCM5708.
Никакие специфические для оборудования настройки не применяются. Мы считаем, что это увеличивает сложность поддержки и снижает заменяемость компонентов.
Нас не интересует connection tracking на 80м порту, поэтому мы его выключаем, чтобы он не мешался
iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp -m tcp --sport 80 -j NOTRACK
Для того, чтобы исходящий трафик не мешал management трафику, на серверах мы делаем приоритезацию с помощью tc.
Мы добавили рутовую дисциплину на интерфейс
qdisc prio 1: dev eth0 bands 4 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
которая рассортировывает трафик на 3 класса из 4, в зависимости от TOS исходящего пакета.
Под TOS тут понимается классический 3-х битный TOS из RFC791 — Delay, Throughput, Reliability, плюс дополнение в виде Monetary Cost из RFC1349. Всего 4 бита и 16 возможных значений/комбинаций. В объявлении дисциплины есть строчка «1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1», которая говорита нам, в зависимости от какого «номера» комбинации на какой из 4х классов отправится пакет. Наша конфигурация дисциплины такая, что пакеты пока будут отправляться только на первые три класса. Мы используем 4-й класс позже.
Дисциплина PRIO старается обслужить сначала пакеты из класса с меньшим номером и перейдет к следующему классу, только когда в текущем очередь пуста. Понятно, что пакеты, которые попадут в 4й класс, будут иметь наименьший приоритет.
Теперь добавим еще одну дисциплину, которая будет обрабатывать пакеты, которые попали в наш 4й класс.
qdisc sfq 2: parent 1:4 limit 128p quantum 1514b
Это сделано для того, чтобы разные TCP сессии отправляли свои пакеты по очереди, вне зависимости от того, в каком порядке они поступили. Limit — это длина общей очереди, если она превысит 128 пакетов, новые будут уничтожаться. Quantum — максимальное количество байт, которое отправится одной сессии, прежде чем дисциплина перейдет к следующей сесии. Все это улучшает т.н. «fairness».
Ну и завернем нужные нам пакеты на 4й класс.
filter parent 1: u32 match ip sport 80 0xffff flowid 1:4
u32 match -- это название фильтра, который может "проверить" любое поле ip пакета. Мы ожидаем полное совпадение (0xffff) части пакета sport (исходящий порт) с числом 80 и отправляем такой пакет на наш 4-й класс рутовой дисциплины.
Материал для самостоятельного изучения по tc находится тут.