Назад | Перейти на главную страницу

HAProxy + nginx достигает максимального значения numtcpsock примерно за 24 часа

Я использую относительно простой VPS (Media Temple (ve)) с несколькими веб-сайтами на основе PHP и (в конечном итоге) с несколькими Узел серверы. Чтобы включить поддержку WebSockets, я использую HAProxy на порту 80, который направляет либо nginx, либо определенный процесс Node.

Однако недавно я столкнулся с проблемой, когда в течение примерно 24 часов мой сервер достигает максимально допустимого количества открытых TCP-соединений (numtcpsock в Parallels Power Panel, который установлен на 1000). Запуск только nginx не вызывает этой проблемы, и в настоящее время у меня нет активных внутренних серверов Node. Nginx подключается к PHP через сокет домена UNIX (и опять же, проблема возникает не только с nginx). Есть мысли о том, что могло вызвать это? Моя конфигурация:

global
    ## 00-base
    maxconn     500
    nbproc      2
defaults
    ## 00-base
    mode        http
frontend all
    ## 00-ports
    bind 0.0.0.0:80
    ## 10-config
    timeout client 86400000
    default_backend nginx
backend nginx
    ## 00-timeouts
    timeout http-keep-alive 5000
    timeout server 10000
    timeout connect 4000
    ## 10-servers
    server main localhost:8000

Заранее спасибо!

ОБНОВИТЬ: после немного lsofЯ смог определить, что более 90% открытых сокетов TCP действительно принадлежат HAProxy, и подавляющее большинство из них находятся в CLOSE_WAIT или FIN_WAIT2 состояния. Это ошибка HAProxy? Это похоже на утечку файлового дескриптора, если только это не неправильная конфигурация с моей стороны.

ОБНОВЛЕНИЕ 2: Я заметил закономерность в lsof вывод. Мне кажется, что происходит то, что nginx закрывает внутреннее соединение с HAProxy, но до того, как HAProxy формально закрывает его, он пытается закрыть внешнее соединение с клиентом (помещая его в FIN_WAIT2). Поскольку FIN никогда не приходит, связь между nginx и HAProxy остается неизменной. CLOSE_WAIT навсегда. Теперь единственный вопрос: почему это происходит?

много сокетов в CLOSE_WAIT - это очень плохо для вашего сервера. Это состояние происходит, когда ядро ​​ожидает, пока программное обеспечение пользовательского пространства не примет закрытие сокета. Если многие сокеты долгое время находятся в этом состоянии - значит, программное обеспечение, использующее их, не отвечает. Обычно сокет в этом состоянии потребляет относительно много времени процессора ядра.

Я полагаю, что CLOSE_WAIT в вашем случае является вторичным по отношению к FIN_WAIT2 - HAproxy ожидает закрытия клиентского соединения и закрывает соединение с NGINX сразу после этого.

FIN_WAIT2 - это состояние ожидания другой стороной подтверждения закрытия сокета. Их не так уж и плохо, но это может указывать на перегрузку сети или большие потери.

Можешь попробовать nolinger вариант с haproxy, чтобы быстрее закрыть соединение. Но будьте осторожны, это нарушит механизм гарантированной доставки tcp.

Проблема вызвана очень большим тайм-аутом. С 24-часовым таймаутом и ограничением до 1000 одновременных подключений вы можете рассчитывать заполнить его клиентами, отключающими грязный путь. Пожалуйста, используйте более разумный тайм-аут, от минут до часов самое большее, действительно нет смысла использовать однодневные тайм-ауты в Интернете. Как сказал DukeLion, система ожидает, пока haproxy закроет соединение, потому что haproxy не получил закрытие от клиента.

Haproxy работает в туннельном режиме для TCP и WebSocket, он следует обычному четырехстороннему закрытию:

- receive a close on side A
- forward the close on side B
- receive the close on side B
- forward the close on side A

В вашем случае я полагаю, что сторона A была сервером, а сторона B - клиентом. Итак, nginx закрылся через некоторое время, сокет перешел в CLOSE_WAIT, haproxy перенаправил близко к клиенту, этот сокет перешел на FIN_WAIT1, клиент ACKed, передал сокет в FIN_WAIT2, а затем ничего не происходит, потому что клиент исчез, что очень часто в сети. И ваш тайм-аут означает, что вы хотите, чтобы это оставалось таким в течение 24 часов.

Через 24 часа ваши сеансы начнут тайм-аут на стороне клиента, поэтому haproxy убьет их и перенаправит close на сторону nginx, избавившись от него тоже. Но очевидно, что вы этого не хотите, WebSocket был спроектирован таким образом, чтобы простаивающее соединение могло быть открыто повторно открыто, поэтому нет причин держать незанятое соединение открытым в течение 24 часов. Никакой брандмауэр не остановит это!