них используется только около 1500 байт (по размеру Ethernet пакета).
mbufs
Для каждого mbuf кластера нужен "mbuf", который имеет размер 256 байт и
нужен для организации связи цепочек из mbuf кластеров. В mbuf можно поместить
полезную информацию в районе 100 байт, но это не всегда используется.
Если в машине 1Гб и больше памяти, то по умолчанию будет создано 25 тыс. mbuf кластеров,
что не всегда достаточно.
При ситуации исчерпания числа свободных mbuf кластеров FreeBSD попадает в
состояние zonelimit и перестает отвечать на запросы по сети,
в top это выглядит как "zoneli". Единственная возможность как-то повлиять на
ситуацию - это зайти с локальной консоли и перезагрузить систему, уничтожить
процесс находящийся в состоянии "zoneli" невозможно. Для Linux 2.6.x данная проблема
тоже характерна, причем работать переставала даже консоль.
PID USERNAME THR PRI NICE SIZE RES STATE TIME WCPU COMMAND
13654 nobody 1 4 0 59912K 59484K zoneli 209:26 0.00% nginx
13654 nobody 1 4 0 59912K 59484K zoneli 209:26 0.00% nginx
Для выхода из этой ситуации существует патч возвращающий приложению ошибку ENOBUFS,
сигнализирующий о попадании в состояние "zoneli", после чего программа может
закрыть лишние соединения. К сожалению патч пока не принят в состав FreeBSD.
Состояние задействованных mbuf кластеров можно посмотреть командой:
>netstat -m 4/1421/1425 mbufs in use (current/cache/total) 0/614/614/25600 mbuf clusters in use (current/cache/total/max) |
Увеличение числа mbuf кластеров во FreeBSD 6.2 можно произвести в любой момент
через параметр kern.ipc.nmbclusters:
sysctl kern.ipc.nmbclusters=65536 |
Для более ранних версий FreeBSD число mbuf кластеров можно было установить только
на этапе загрузки:
/boot/loader.conf: kern.ipc.nmbclusters=65536 25000 mbuf clusters = 55M 32768 mbuf clusters = 74M 65536 mbuf clusters = 144M |
25000 mbuf кластеров занимают примерно 50Мб памяти, 32000 - 74 Мб, 65000 -
144Мб (рост по степени 2). 65000 - пограничное значение, превышать которое не
рекомендуется, без предварительного расширения адресного пространства
доступного ядру.
Увеличение памяти, доступной ядру
Увеличение адресного пространства ядра, которое на i386 платформе - 1Гб.
Для увеличения до 2Гб, в файле конфигурации ядра необходимо указать:
options KVA_PAGES=512 |
На платформе amd64 KVA всегда 2G, увеличить к сожалению в настоящее время нельзя.
Кроме увеличения виртуального адресного пространства можно увеличить лимит
физической памяти, которую может использовать ядро (по умолчанию 320Мб). Увеличим
до 1Гб:
/boot/loader.conf: vm.kmem_size=1G |
Затем выделим из него 575Мб под mbuf кластера:
sysctl -w kern.ipc.nmbclusters=262144 |
Установление соединения. syncache и syncookies
Примерно 1000 байт расходуется на одно соединение.
Примерно 100 байт для одной записи на незаконченное соединение в syncache.
Всего можно держать в памяти информацию об около 15000 соединениях.
Параметры syncache можно посмотреть через "sysctl net.inet.tcp.syncache" (доступен
в режиме только для чтения):
# sysctl net.inet.tcp.syncache net.inet.tcp.syncache.bucketlimit: 30 net.inet.tcp.syncache.cachelimit: 15359 net.inet.tcp.syncache.count: 29 net.inet.tcp.syncache.hashsize: 512 net.inet.tcp.syncache.rexmtlimit: 3 |
Изменить параметры syncache можно только на этапе загрузки ядра:
/boot/loader.conf: net.inet.tcp.syncache.hashsize=1024 net.inet.tcp.syncache.bucketlimit=100 |
Когда новое соединение не помещается в переполненный syncache, FreeBSD переходит в
режим "syncookies" (TCP SYN cookies). Включается возможность такого перехода через:
sysctl net.inet.tcp.syncookies=1 |
Заполненность syncache и статистику по syncookies можно посмотреть через команду:
netstat -s -p tcp ... 2079088720 syncache entries added ... > 0 dropped 2058506523 completed > 0 bucket overflow > 0 cache overflow ... 0 cookies sent 0 cookies received |
После того как соединение принято оно попадает в "listen socket queue".
Статистику можно посмотреть командой
netstat -Lan Current listen queue sizes (qlen/incqlen/maxqlen) Proto Listen Local Address tcp4 43/0/4096 *.80 tcp4 0/0/128 *.22 |
4096 - размер очереди (максимум 65тыс.)
43 - заполненность очереди в данный момент (приложение не вытащило из очереди).
Увеличение размера очереди производится через:
sysctl kern.ipc.somaxconn=4096 |
После того как соединение принято для него FreeBSD создает структуры связанные
с сокетами (sockets).
Увеличить максимальное число открытых сокетов во FreeBSD 6.2, во время работы,
можно через:
sysctl kern.ipc.maxsockets=204800 |
В более ранних версиях:
/boot/loader.conf: kern.ipc.maxsockets=204800 |
Посмотреть состояние можно командой:
vmstat -z ITEM SIZE LIMIT USED FREE REQUESTS FAILURES ... socket: 356, 204809, 48041, 114869, 4292783585, 0 ... inpcb: 180, 204820, 63956, 121460, 4283258030, 0 tcpcb: 464, 204800, 48015, 114897, 4283258030, 0 |
tcb hash
Если машина обрабатывает несколько десятков тысяч соединений то tcb hash позволяет быстро
определять принадлежность пришедшего пакета к определенному соединению.
По умолчанию размер tcb hash - 512 элементов.
Текущий размер можно посмотреть через sysctl (только для чтения):
sysctl net.inet.tcp.tcbhashsize |
Изменить можно на этапе загрузки:
/boot/loader.conf: net.inet.tcp.tcbhashsize=4096 |
Файлы
Приложения работают не с сокетами, а с файлами. По этому для каждого
сокета нужна структура, которая описывает файл. Увеличить можно через:
sysctl kern.maxfiles=204800 sysctl kern.maxfilesperproc=200000 |
kern.maxfiles - всего файлов в системе
kern.maxfilesperproc - максимальное число файлов на один процесс.
Параметры можно менять на работающей системе, но они не отразятся на уже запущенных
процессах. Поэтому в nginx были добавлены директивы позволяющие менять число
открытых файлов для уже запущенных процессов (после инициирования операции переконфигурации)
nginx.conf: worker_rlimit_nofile 200000; events { worker_connections 200000; } |
receive buffers
Буферы для приема данных. По умолчанию 64Kб, если нет загрузки больших объемов данных,
то можно уменьшить до 8Кб (меньше вероятность переполнения при DoS атаке).
sysctl net.inet.tcp.recvspace=8192 |
Для nginx:
nginx.conf: listen 80 default rcvbuf=8k; |
send buffers
Буферы для отправки данных. По умолчанию 32K. Если скачиваются данные небольшого объема
или недостаток mbuf кластеров, можно уменьшить:
sysctl net.inet.tcp.sendspace=16384 |
Для nginx:
nginx.conf: listen 80 default sndbuf=16k; |
В ситуации когда сервер записал в сокет данные, но клиент не хочет их забирать,
после таймаута по закрытию соединения в ядре данные будут держаться еще
несколько минут. В nginx если директива для принудительного сброса всех данных
после закрытия по таймауту.
nginx.conf: reset_timedout_connections on; |
sendfile
Еще один механизм для экономии mbuf кластеров - это sendfile, он использует
память буферов ядра с данными файлов одновременно для передачи этих данных в
сетевую карту, без промежуточного заполнения лишних буферов.
В nginx включается:
nginx.conf: sendfile on; |
На i386 по умолчанию для систем с 1 или более Гб памяти будет выделено 6656
sendfile буферов. Этого вполне достаточно. На платформе amd64 более оптимальный
вариант реализации и sfbufs буферы не нужны.
Статистика:
i386>netstat -m ... 190/510/6656 sfbufs in use (current/peak/max) amd64>netstat -m ... 0/0/0 sfbufs in use (current/peak/max) |
При переполнении sendfile буфера процесс замирает в состоянии "sfbufa", но
ситуация достаточно быстро приходит в норму после увеличения размера буфера.
PID USERNAME THR PRI NICE SIZE RES STATE TIME WCPU COMMAND 13654 nobody 1 4 0 59912K 59484K sfbufa 209:26 5.00% nginx |
Увеличение размера через:
/boot/loader.conf: kern.ipc.nsfbufs=10240 |
TIME_WAIT
После того как соединение закрывается сокет переходит в состояние TIME_WAIT
В этом состоянии он может находится по умолчанию в течение 60 секунд.
Время можно изменить через sysctl (в миллисекундах деленных на 2, 2 x 30000 MSL = 60 секунд):
sysctl net.inet.tcp.msl=30000 |
Во FreeBSD 6.2 TIME_WAIT сокеты обрабатываются отдельно (нужна лишь
часть информации 48 байт из 1 Кб. Ограничение вне лимита
kern.ipc.maxsockets), число их регулируется параметром:
sysctl net.inet.tcp.maxtcptw=40960 |
Статистика:
>vmstat -z ITEM SIZE LIMIT USED FREE REQUESTS FAILURES ... tcptw: 48, 41028, 15941, 25087, 1045159949, 438573 |
TCP/IP ports
По умолчанию исходящие соединения инициируются с диапазона портов 49152-65535 (16 тыс.).
Их неплохо увеличить (1024-65535):
sysctl net.inet.ip.portrange.first=1024 sysctl net.inet.ip.portrange.last=65535 |
Для использования портов по порядку, вместо случайной выборки (для
исключения ошибки повторного коннекта с одного порта до отработки
TIME_WAIT):
sysctl net.inet.ip.portrange.randomized=0 |
Во FreeBSD 6.2 появилась возможность не создания состояния TIME_WAIT для
соединений в рамках localhost:
sysctl net.inet.tcp.nolocaltimewait=1 |
п.с.
А что случилось с Андреем? Почему он должен унывать?
возможно у Вас отключен javascript, если включен - просто обновите страницу