Подстройка ядра FreeBSD под нагрузку OpenTracker

     Трекер потихоньку набрал популярность неизвестно среди кого :) и начал жрать сетевые ресурсы ядра. Я навалял небольшой шаблон к кактусу для мониторинга трекера, но кактус что-то недавно сломался так что об этом как-нибудь потом. За 2 месяца число активных пиров на трекере перевалило за 500-600к, с нагрузкой примерно в 1к транзакций в секунду (сложно сказать точнее, т.к. статистика у опентрекера довольно странная). В мегабитах трафика нагрузка небольшая но в pps и числе уникальных соединений для нетюненного ядра оказалось многовато. Пришлось его потихоньку подкручивать до состояния – чтобы не падало. Это небольшая заметка о том что где и зачем накрутил.В гугле навалом “затюненых” конфигов под фрю, основаных на стенограмме Сысоева про настройку FreeBSD под высоконагруженный nginx. Сам по себе доклад очень познавательный и интересный, но в большинстве “затюненых” конфигов на его основе тупо задраны  до небес все sysctl до которых руки дотянулись без каких-либо “зачем” и “почему”, результатов мониторинга или тестов. Вот, например, забавно… человек, вроде, роутер собирает и накручивает tcp буфера и очередь соединений до небес – наверное, роутер будет терминировать тучу ssh-туннелей сессиями по 8к :)  Вобщем крутить надо оглядываясь на здравый смысл, а не на доки, тем паче что роутер с опентрекером это всего лишь нетоп на атоме, а не боевой сервак.

Но по порядку…

Самым первым и практически сразу загнулся ipfw в котором я по началу открыл доступ к порту opentracker’а через динамическое правило. Естественно сонмища коннектов с разных адресов быстро забили максимальный лимит по динамическим правилам. Ну тут вобщем-то делов на пару строчек – переписать правила ipfw  с динамики на статику по порту трекера. Дальше трекер вполне жил себе какое-то время пока не подвалило еще пиров.  Собственно сетевая нагрузка на трекер довольно специфична – большое количество короткоживущих tcp-сессий с уникальных адресов. Сделав один запрос клиент уходит и в следующий раз вернется в лучшем случае через пол часа (дефолт анонса на трекер). Собственно данных в рамках сессии передается очень мало, обычно запрос целиком влезает в 1 ip-пакет и также влезает и ответ. Но ради этих 2х пакетов приходится сначала устанавливать а потом завершать сессию, это еще 7 паектов минимум, при уловии что ни один из них нигде не потеряется. Становится понятно почему openbittorrent.com и publicbt.com прекратили поддержку tcp и перешли на чистый udp.  Tcp для трекера это тупая трата ресурсов сети и системы и останется уделом закрытых трекеров с регистрациями, паскеями, рейтингами и прочими няшками для кармадрочерства.

Ну к баранам…  Следующим этапом у меня закончились ресурсы для TCP TIME_WAIT. В  TIME_WAIT соединение переходит после отправки fin (а в случае с трекером – это практически всегда сервер, т.к. он первый закрывает соединение). В таком состоянии сокет болтается еще некоторое время дабы предотвратить повторное использование пары адрес:порт с тем же хостом в рамках другого соединения, если вдруг один из пакетов завершения сессии застрянет в сети на некоторое время. Подробнее написано в RFC 1337 или здесь По умолчанию это вермя равно 2xMSL (Maximum segment lifetime) или 60 sec для freebsd. Если прикинуть что сервер обрабатывает 1к уников в секунду, то прежде чем старые tcptw начнут протухать через минуту, сервак наловит уже 60к новых. Для трекера вероятность получить вторую сессию с темже клиентом по тому же порту  равна ноль целых хрен десятых, да и пёс бы с ним , но … стандарт есть стандарт. Вобщем-то параметр не смертельный, для  tcptw используются не стандартные сокеты из числа kern.ipc.maxsockets, а более урезанные структуры, памяти тратится меньше и система не встает раком при их исчерпании. Параметры в ядре отвечающие за time wait

  • net.inet.tcp.maxtcptw – число структур, по умолчанию  равен 5150
  • net.inet.tcp.msl maximum segment lifetime (defailt 30000), задается в ms. Время жизни сокета в состоянии  TIME_WAIT определяется как 2 x MSL

Сначала я подрезал   net.inet.tcp.msl до 10000, тобишь сократил время жизни TIME_WAIT до 20 сек., потом начал потихоньку увеличивать net.inet.tcp.maxtcptw  пока он перестал переполняться.

Посмотреть статистику использования  TIME_WAIT  можно так:

Результат сохраняем в /etc/sysctl.conf

# Maximum segment lifetime
# timeout for TIME_WAIT connections is msl x2 (default 60 sec)
# Default: 30000 ms
net.inet.tcp.msl=10000

# Maximum number of TCP TIME_WAIT entries
#Default: 5150
net.inet.tcp.maxtcptw=32768

Дальше трекер снова зажил спокойно на некоторое время пока в системе не кончились сокеты. А когда заканчиваюстся сокеты все становится очень печально. Сервер больше не может принимать никакие соединения пока они не освободятся. А что делают торрент-клиенты когда не могут подключится к трекеру? – правильно долбятся снова и вовсе не через пол часа. Вобщем-то я уже замечал что после перезагрузки сервера число конектов к трекеру резко вырастает, а потом также резко спадает, этот волнообразный процесс хорошо видно на графиках и как он постепенно волнообразно затухает с периодом в пол часа Прям как гармонический маятник  :)  Вобщем когда кончились сокеты – все встало в позу зю, сервак отшибал все сетевые соединения, в.т.ч. ssh, консоли под рукой не было – пришлось его перегрузить. После перезагрузки был сюрприз – не стартовал ssh. Как выяснилось (непонятно почему) ssh стартует при загрузке системы довольно поздно, гораздо позднее прочих демонов в.т.ч.  mpd и opentracker’а. К тому моменту как он запустился трекер уже был выставлен в инет и снова мигом сожрал все сокеты (пиры то уж заждались пока роутер перегружался). Пичалька… Пришлось подрихтовать его стартовый скрипт  и сказать ему что бы он не запускался раньше sshd

 /usr/local/etc/rc.d/opentracker

– # REQUIRE: LOGIN

+ # REQUIRE: LOGIN sshd

Дальше сокеты… Состояние по сокетам можно посмотреть через vmstat. Когда все умерло там было вот так

> vmstat -z | head -1 && vmstat -z | grep -E “inpcb|socket”
ITEM SIZE LIMIT USED FREE REQ FAIL SLEEP
socket: 680, 25602, 22936, 2096, 8631696, 0, 0
udp_inpcb: 392, 25600, 19, 111, 3668, 0, 0
tcp_inpcb: 392, 25600, 25598, 2, 799416,7828014, 0

За количество доступных сокетов в ядре отвечает параметр kern.ipc.maxsockets по умолчанию 25600. Если не хватает 25к, то при всплесках может не хватить и 32к, я увеличил значение до 65536, посмотрим как оно будет жить.  Число открытых сокетов в данный момент можно посмотреть через sysctl kern.ipc.numopensockets

Еще одним важным параметром сетевой настройки является kern.ipc.nmbclusters – число mbuf кластеров (блоков памяти) для хранения сетевых  данных. Очень популярный параметр для “увеличения” во многих постах в сети.

Статистику по использованию mbuf и mbuf кластеров можно посмотреть через netstat

Вобщем-то понятно что увеличивать тут ничего не надо, до лимита еще очень далеко. Оно не особо удивительно – трафик трекер генерит совсем небольшой и сессии быстро закрываются, поэтому ресурсы успевают освобождаться. Для jumbo используютя отдельные mbufs увеличенного размера. На одном из интерфейсов у меня включен jumbo поэтому видно что часть 9к кластеров используется. 4к кластеры могут использоваться для отправки данных в соединениях, там еще есть запас – можно ничего не трогать.

Параметр kern.ipc.somaxconn – тоже любят везде увеличивать. Определяет размер очереди для соединений которые ядро уже приняло, а приложение еще не выдернуло на обработку и вовсе не определяет количество  “окучиваемых” соединений.

> netstat -Lan | grep 2710
tcp6 0/0/128 2002:d58d:x:1.2710
tcp6 0/0/128 2002:d58d:x::.2710
tcp4 0/0/128 *.2710

Как видно из статистики у меня при очереди 128 opentracker “окучивает” ~1k запросов в секунду, при этом очередь пуста. Это значит что окучивает он их быстрее чем они поступают. Увеличивать тут ничего не надо, кроме того если приложение перестанет успевать обрабатывать соединения – увеличение очереди не всегда панацея.

 Есть еще куча настроек tcp, но я так поглядел – там ничего страшного вроде не кончилось, так что особо ничего не крутил. Статистику по syncache и syncookies можно посмотреть по netstat -s -p tcp

Корзинки для  syncache  у меня уже были увеличены до 50 раньше в loader.conf от умолчальных 30 (net.inet.tcp.syncache.bucketlimit=50). Переполнений по кешу и по корзинкам не было.  Какие-то еще переменные у меня были отличны от умолчальных, но уже не помню где и по какой причине. Мож в следующий раз этот пост поможет.

 Будем смотреть что дальше закончится в системе :)

Вот, кстати, нашел в бсдшной рассылке уже подкручивавших настройки под опентрекер на h3q.com :)

Если и у меня трафик вырастет до 10 мегабит – придется сворачивать лавку :)

2 Responses to Подстройка ядра FreeBSD под нагрузку OpenTracker

  1. Фрэнсис:

    автору респект, как раз искал советы как подтюнить фрю именно под опентрекер. а тут на русском даже )
    как кстати можно связаться с автором…с целью обмена знаниями и не только.

    • emil:

      Автор где-то рядом :) Забросил как-то блог, все недосуг. Можно писать сюда или в почту.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">