поправки к "100-200 тысяч соединений" для FreeBSD 7 ( i386 и amd64 )
Alexey V. Karagodov
kav at karagodov.name
Sun Jun 1 05:09:54 MSD 2008
Keywords: freebsd tcp optimization tune speed socket mbuf sendfile
sysctl
From: Сысоев Игорь Владимирович <http://
www.sysoev.ru>
Date: Mon, 1 Oct 2007 14:31:37 +0000 (UTC)
Subject: FreeBSD для обслуживания 100-200 тысяч
соединений
[[http://rutube.ru/tracks/125719.html?v=23351111db90ae8beace6a841dd2a8f4%EE%C1%D3%D4%D2%CF%CA%CB%C1
Видеоролик доклада]]
######## мои дополнения отмечены ######## в
начале строки
######## в самом низу даны "итоговые" файлы
конфигурации /boot/loader.conf /etc/sysctl.conf и ядер
для i386 и amd64
Стенограмма выступления Игоря Сысоева
с конференции РИТ-2007.
mbuf clusters
FreeBSD хранит сетевые данные в mbuf clusters,
размер каждого 2Кб, но из
них используется только около 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
Для выхода из этой ситуации существует
патч возвращающий приложению ошибку
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 оказалось недостаточно
указать vm.kmem_size_max=1G в /boot/loader.conf,
######## (параметр был просто игнорирован)
по-этому это надо сделать в файле
конфигурации ядра:
######## options VM_KMEM_SIZE=1073741824
######## options VM_KMEM_SIZE_MAX=1073741824
На платформе amd64 KVA всегда 2G, увеличить
к сожалению в настоящее время нельзя.
Кроме увеличения виртуального
адресного пространства можно
увеличить лимит
физической памяти, которую может
использовать ядро (по умолчанию 320Мб).
Увеличим
до 1Гб:
/boot/loader.conf:
vm.kmem_size=1G
######## для обеих платформ добавить
vm.kmem_size_max=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
######## /usr/src/sys/amd64/conf/CUSTOM
include GENERIC
device pf
device pflog
device pfsync
device carp
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_CDNR
options ALTQ_PRIQ
options ALTQ_NOPCC
#options QUOTA
options IPSEC
#options IPSEC_FILTERGIF
device crypto
device cryptodev
options DEVICE_POLLING
#options HZ=1000
#options SCHED_ULE
#options KVA_PAGES=512
options VM_KMEM_SIZE=1073741824
options VM_KMEM_SIZE_MAX=1073741824
options PANIC_REBOOT_WAIT_TIME=60
ident CUSTOM
######## /usr/src/sys/i386/conf/CUSTOM
include GENERIC
device pf
device pflog
device pfsync
device carp
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_CDNR
options ALTQ_PRIQ
options ALTQ_NOPCC
#options QUOTA
options IPSEC
#options IPSEC_FILTERGIF
device crypto
device cryptodev
options DEVICE_POLLING
#options HZ=1000
#options SCHED_ULE
options KVA_PAGES=512
options VM_KMEM_SIZE=1073741824
options VM_KMEM_SIZE_MAX=1073741824
options PANIC_REBOOT_WAIT_TIME=60
ident CUSTOM
######## /boot/loader.conf
verbose_loading="YES"
loader_logo="beastie"
#ng_ether_load="YES"
#linux_load="YES"
accf_data_load="YES"
accf_http_load="YES"
net.inet.tcp.syncache.hashsize=1024
net.inet.tcp.syncache.bucketlimit=100
net.inet.tcp.tcbhashsize=4096
kern.ipc.nsfbufs=10240
vm.kmem_size=1G
vm.kmem_size_max=1G
######## /etc/sysctl.conf
net.inet.tcp.blackhole=1
net.inet.udp.blackhole=1
kern.ipc.nmbclusters=262144
kern.ipc.somaxconn=4096
kern.ipc.maxsockets=204800
kern.maxfiles=204800
kern.maxfilesperproc=200000
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65535
net.inet.ip.portrange.randomized=0
net.inet.tcp.recvspace=8192
net.inet.tcp.sendspace=16384
net.inet.tcp.maxtcptw=40960
net.inet.tcp.msl=30000
net.inet.tcp.syncookies=1
net.inet.tcp.nolocaltimewait=1
net.inet.tcp.fast_finwait2_recycle=1
######## после всех мытарств, работа
системы весьма порадовала.
######## комменты только приветствуются.
######## огромное пожелание к Игорю
включить сей опус с поправками и
комментариями (кои лично меня ОЧЕНЬ
интересуют) в документацию на своём
сайте.
######## данные конфиги являются
результатом печального опыта. если не
указывать vm.kmem_size_max, ядру нехватит
памяти, для всей этой красоты.
######## успехов
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://nginx.org/pipermail/nginx-ru/attachments/20080601/6e73546c/attachment.html>
More information about the nginx-ru
mailing list