The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

FreeBSD для обслуживания 100-200 тысяч соединений (freebsd tcp optimization tune speed socket mbuf sendfile sysctl)


<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>
Ключевые слова: 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 тысяч соединений Видеоролик доклада Стенограмма выступления Игоря Сысоева с конференции РИТ-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 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
Дополнение от Alexey V. Karagodov <kav@karagodov.name.> для amd64 оказалось недостаточно указать vm.kmem_size_max=1G в /boot/loader.conf, (параметр был просто игнорирован) по-этому это надо сделать в файле конфигурации ядра: options VM_KMEM_SIZE=1073741824 options VM_KMEM_SIZE_MAX=1073741824 В /boot/loader.conf для обеих платформ нужно добавить vm.kmem_size_max=1G Итоговый /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 # ядро для i386 нужно собрать с "options KVA_PAGES=512" vm.kmem_size_max=1G /etc/sysctl.conf net.inet.tcp.blackhole=1 net.inet.udp.blackhole=1 kern.ipc.nmbclusters=0 # Отсутствие ограничений на размер зоны 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.maxtcptw=40960 net.inet.tcp.msl=30000 net.inet.tcp.syncookies=1 net.inet.tcp.nolocaltimewait=1 net.inet.tcp.fast_finwait2_recycle=1

<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>

Обсуждение [ Линейный режим | Показать все | RSS ]
  • 1.1, e1ektr0n (?), 07:46, 11/10/2007 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    мда, мне до етих знаний исчо учиться и учиться :-(
     
     
  • 2.2, bytestore (??), 09:46, 11/10/2007 [^] [^^] [^^^] [ответить]  
  • +/
    Респект! еще бы мне научится все это расчитывать в цифрах, так сказать формула сервера :)
     

  • 1.3, sld (?), 11:45, 16/10/2007 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Ошибка в options KVA_PAGE=512
    пишеться options KVA_PAGES=512
     
     
  • 2.4, С.А. (?), 18:57, 11/11/2007 [^] [^^] [^^^] [ответить]  
  • +/
    да хрен с ними, с опечатками.
    Игорю Сысоеву огромное спасибо!
     
  • 2.11, Аноним (-), 09:39, 12/04/2012 [^] [^^] [^^^] [ответить]  
  • +1 +/
    Ошибка в "пишеться".
    "пишеться" пишется "пишется".
     

  • 1.5, Аноним (5), 13:45, 13/11/2007 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    "В mbuf можно поместить
    полезную информацию в районе 100 байт, но это не всегда используется"
    mbuf = m_hdr + m_dat, m_hdr = 22 байта, m_dat = 234 байта,  если mbuf имеет флаг M_PKTHDR, будет сокращение с 234 до 210 байтов,,,,  100 байт никак не получается,,,,,,,  
     
  • 1.6, Gigli (?), 16:15, 31/03/2008 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    На конференции еще речь шла о некорректном поведении фри при достижении некоторых лимитов, и Сысоев обещал поделиться патчем, но почему-то тема так и забылась, а проблема вроде как актуальна и по сей день.
    И еще хотелось бы узнать, как все это будет жить на FreeBSD 7, что еще нужно(?) подкрутить?
     
  • 1.8, Ax2M (?), 17:27, 11/04/2010 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Ошибка с reset_timedout_connections  on;
    надо reset_timedout_connection  on;
    мелочь конечно, но все же...

     
  • 1.9, invader (?), 20:39, 09/07/2010 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Супер! Недавно собирался менять свой сервер, а после прочтения этой статьи отложыл года так на полтора! Респект, Игорью!
     
  • 1.10, ... (?), 14:46, 15/08/2010 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Да, выжимайте из своего сервера ВСЕ соки :)
     
  • 1.12, Sergey (??), 00:34, 23/02/2013 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Ребят, на дворе 2013 дела как-то изменились? Поделитесь опытом.
     
  • 1.13, Alex (??), 09:12, 05/07/2013 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Поддерживаю вопрос Sergey. Уже 2013-й и фря 9.1 Что-то изменилось??
     
  • 1.14, Alexey V. Karagodov (?), 01:06, 14/11/2014 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    https://calomel.org/freebsd_network_tuning.html
     
  • 1.15, Ldar (??), 12:11, 07/01/2018 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Вот это еще можно смотреть, как отправную точку.

    https://wiki.freebsd.org/NetworkPerformanceTuning
    man tunning
    man tcp
    man ip

     

    игнорирование участников | лог модерирования

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру