Сегодня у нас возникла небольшая проблема переключения при отказе с одной из наших виртуальных машин HAProxy. Когда мы покопались в ней, мы обнаружили следующее:
Jan 26 07:41:45 haproxy2 kernel: [226818.070059] __ratelimit: 10 callbacks suppressed Jan 26 07:41:45 haproxy2 kernel: [226818.070064] Out of socket memory Jan 26 07:41:47 haproxy2 kernel: [226819.560048] Out of socket memory Jan 26 07:41:49 haproxy2 kernel: [226822.030044] Out of socket memory
Который, на эта ссылка, по-видимому, связано с низкими настройками по умолчанию для net.ipv4.tcp_mem
. Поэтому мы увеличили их в 4 раза по сравнению со значениями по умолчанию (это Ubuntu Server, не уверен, имеет ли значение вариант Linux):
current values are: 45984 61312 91968 new values are: 183936 245248 367872
После этого мы начали видеть странное сообщение об ошибке:
Jan 26 08:18:49 haproxy1 kernel: [ 2291.579726] Route hash chain too long! Jan 26 08:18:49 haproxy1 kernel: [ 2291.579732] Adjust your secret_interval!
Тсс .. это секрет!!
Очевидно, это связано с /proc/sys/net/ipv4/route/secret_interval
по умолчанию 600 и контролирует периодическая очистка кеша маршрута
В
secret_interval
указывает ядру, как часто удалять ВСЕ записи хэша маршрута, независимо от того, насколько они новые / старые. В нашей среде это вообще плохо. ЦП будет занят восстановлением тысяч записей в секунду каждый раз при очистке кеша. Однако мы установили его запуск один раз в день, чтобы предотвратить утечки памяти (хотя у нас их никогда не было).
Хотя мы рады уменьшить это, кажется странным рекомендовать удалять весь кеш маршрута через определенные промежутки времени, а не просто быстрее выталкивать старые значения из кеша маршрутов.
После некоторого расследования мы обнаружили /proc/sys/net/ipv4/route/gc_elasticity
что кажется лучшим вариантом для контроля размера таблицы маршрутов:
gc_elasticity
лучше всего можно описать как среднюю глубину сегмента, которую примет ядро, прежде чем оно начнет истекать записи хэша маршрута. Это поможет поддерживать верхний предел активных маршрутов.
Мы изменили эластичность с 8 до 4 в надежде на более агрессивную очистку кеша маршрутов. В secret_interval
не кажется нам правильным. Но есть множество настроек, и неясно, какие из них действительно правильные.
Мы не хотим делать маршрутизацию Linux хуже, поэтому мы как бы боимся связываться с некоторыми из этих настроек.
Может ли кто-нибудь посоветовать, какие параметры маршрутизации лучше всего настроить для экземпляра HAProxy с высоким трафиком?
Никогда не сталкивался с этой проблемой. Однако вам, вероятно, следует увеличить ширину хэш-таблицы, чтобы уменьшить ее глубину. Используя "dmesg", вы увидите, сколько записей у вас сейчас:
$ dmesg | grep '^IP route'
IP route cache hash table entries: 32768 (order: 5, 131072 bytes)
Вы можете изменить это значение с помощью параметра командной строки загрузки ядра. rhash_entries
. Сначала попробуйте вручную, а затем добавьте в свой lilo.conf
или grub.conf
.
Например: kernel vmlinux rhash_entries=131072
Возможно, у вас очень ограниченная хеш-таблица, потому что вы выделили небольшой объем памяти вашей виртуальной машине HAProxy (размер хеш-функции маршрута регулируется в зависимости от общего объема ОЗУ).
Что касается tcp_mem
, быть осторожен. Ваши первоначальные настройки заставляют меня думать, что вы используете 1 ГБ ОЗУ, 1/3 из которых может быть выделена для сокетов TCP. Теперь вы выделили 367872 * 4096 байт = 1,5 ГБ ОЗУ для сокетов TCP. Вы должны быть очень осторожны, чтобы не исчерпать память. Практическое правило - выделить 1/3 памяти для HAProxy, еще 1/3 - для стека TCP и последнюю 1/3 - для остальной части системы.
Я подозреваю, что ваше сообщение "закончилась память сокета" исходит из настроек по умолчанию в tcp_rmem
и tcp_wmem
. По умолчанию для каждого сокета выделено 64 КБ на выходе и 87 КБ на входе. Это означает всего 300 КБ для прокси-соединения, только для буферов сокетов. Добавьте к этому 16 или 32 КБ для HAProxy, и вы увидите, что с 1 ГБ ОЗУ вы будете поддерживать только 3000 подключений.
Изменив настройки по умолчанию tcp_rmem
и tcp_wmem
(средний параметр), вы можете получить намного меньше памяти. Я получаю хорошие результаты с такими низкими значениями, как 4096 для буфера записи и 7300 или 16060 в tcp_rmem
(5 или 11 сегментов TCP). Вы можете изменить эти настройки без перезапуска, однако они будут применяться только к новым соединениям.
Если вы предпочитаете не трогать sysctls слишком много, последняя версия HAProxy, 1.4-dev8, позволяет вам настраивать эти параметры из глобальной конфигурации и для каждой стороны (клиента или сервера).
Надеюсь, это поможет!
В Out of socket memory error
часто вводит в заблуждение. В большинстве случаев на серверах с выходом в Интернет это не указать на любую проблему, связанную с нехваткой памяти. Как я объяснил более подробно в сообщение в блоге, наиболее частая причина - количество "сиротских" розеток. Сиротский сокет - это сокет, не связанный с файловым дескриптором. В определенных обстоятельствах ядро выдаст Out of socket memory error
даже если вы в 2 или 4 раза отошли от лимита (/proc/sys/net/ipv4/tcp_max_orphans
). Это часто случается в службах с выходом в Интернет и является нормальным явлением. Правильный курс действий в этом случае - настроить tcp_max_orphans
быть как минимум в 4 раза больше сирот, которых вы обычно видите с пиковым трафиком.
Не слушайте никаких советов, которые рекомендуют тюнинг tcp_mem
или tcp_rmem
или tcp_wmem
если только ты не действительно знаю, что делаешь. Те, кто дает такие советы, обычно этого не делают. Их вуду часто не подходит для вашего окружения и не решит вашу проблему. Может быть, даже хуже.
Мы регулярно настраиваем некоторые из этих параметров. Наш стандарт для торговых платформ с высокой пропускной способностью и малой задержкой:
net.ipv4.tcp_rmem = 4096 16777216 33554432 net.ipv4.tcp_wmem = 4096 16777216 33554432 net.ipv4.tcp_mem = 4096 16777216 33554432 net.core.rmem_default = 16777216 net.core.wmem_default = 16777216 net.core.rmem_max=16777216 net.core.wmem_max=16777216 net.core.netdev_max_backlog = 30000 net.core.netdev_max_backlog = 30000