Прощупываем angie внутри своей компании. Пытаемся переносить конфигурации с действующих nginx на свежую версию angie, после перекомпиляции модулей angie и попытки старта сервиса angie он выпадает с ошибкой
ngx_slab_alloc() failed: no memory in upstream zone xxxx
После увеличения памяти апстрим зоне примерно в 8 раз сервис angie поднимается и работает стабильно. При этом со старой конфигурацией (с меньшим объёмом памяти) nginx работает успешно.
Так же, при успешно запущенном angie, после обратного уменьшения памяти в апстрим зоне , сервис angie успешно релоадится (не рестартится) и применяет изменения.
Итого:
Первый старт сервиса невозможен со старыми настройками памяти апстрим зон.
Релоад сервиса после уменьшения памяти проходит успешно, изменения применяются
Последующий рестарт сервиса с “меньшим” значением памяти выпадает с той же ошибкой.
Подробная статистика по каждому upstream-серверу хранится в разделяемой памяти. В nginx такой статистики в принципе не было, поэтому там требовалось меньше памяти под каждый сервер в блоке upstream. Но речь идет всего о нескольких дополнительных килобайт на каждый сервер. Если в блоке upstream указано доменное имя, то оно может резолвится в несколько серверов.
Видимо ранее размер зоны был сконфигурирован совсем крохотным?
Повторить эксперимент с уменьшением памяти и релоадом - у меня не получилось. На моей конфигурации каждый раз получал такую же ошибку при попытке уменьшить размер зоны и сервер продолжал работать с предыдущей конфигурацией, где памяти хватает.
В связи с этим просьба показать конфигурации, на которой это воспроизводится.
Если вы имеет в виду подробную статистику, которая “включается” директивой api, которой в nginx нет, то она не включена и в нашем окружении.
Фактически мы просто скопировали виртуальную машину с nginx, развернули на нём angie и пытаемся запустит сервис с той же конфигурацией (не считая смены pid в конфигурации и перекомпилирования модулей). Никаких фич, которые предоставляет angie мы не включаем, ни резолвер, ни апи.
Если говорить о конфигурации, то в конфигурации апстримов находится 40 серверов указанных в виде DNS имени, которые резолвятся только в один IP адрес (к теме про резолв в несколько адресов).
Мы посчитали что такое поведение обусловленно именно рестартом сервиса (не релоадом) и решили рестартнуть наши nginx сервисы, но они рестартнули успешно.
Более того, заметили интересную особенность.
При уменьшении размера памяти апстрим зоны с 3 бэкендами с 64кб до 2кб и прокатке команды nginx -t - нгинкс ругается “nginx: [emerg] zone “xxxx” is too small”
При уменьшении размера памяти апстримы зоны с 40 бэкендами, с “рабочих” 512кб до 2кб на сервере с angie при тестировании конфига (angie -t) сервис не ругается, при релоаде сервиса - релоадится успешно, при рестарте - ожидаемая ошибка.
Возможно angie использует какой-то другой метод “подсчёта” алоцируемой памяти в апстрим зонах?
Метрики считаются всегда, когда сервер собран с модулем API. С точки зрения производительности - гораздо дешевле увеличивать счетчики, чем на каждый счетчик делать отдельную проверку - включена ли где-то в конфигурации директива api или нет.
Точно также ведет себя и модуль stub_status в nginx - если он собран, то на счетчики выделяется память и они считаются постоянно.
Уменьшил размер зоны до 2k, при reload получил:
2023/07/20 20:28:40 [notice] 23505#23505: signal process started
2023/07/20 20:28:40 [emerg] 23482#23482: zone "one" is too small in /home/vbart/Development/angie/build/../test.conf:15
Аналогично с angie -t:
% sbin/angie -t -c ../test.conf
angie: [emerg] zone "one" is too small in /home/vbart/Development/angie/build/../test.conf:15
angie: configuration file /home/vbart/Development/angie/build/../test.conf test failed
Данная ошибка выдается когда указанное в директиве zone значение меньше, чем 8 страничек памяти. Соответствующее условие в коде nginx при проверке синтаксиса директивы:
В Angie эта проверка никак не менялась:
Как и вообще не менялся код функции, обрабатывающий данную директиву.
Можете привести минимальный пример конфигурации, на котором наблюдалось у вас такое поведение? И укажите пожалуйста на какой системе? Angie установлен из наших пакетов?
server {
listen 80;
server_name test.domain.com;
access_log /var/log/nginx/test.domain.com.access.log main;
error_log /var/log/nginx/test.domain.com.error.log;
include /etc/nginx/access_list/list1.list;
include /etc/nginx/access_list/list2.list;
deny all;
set $my_real_ip $remote_addr;
if ($http_x_real_ip) {
set $my_real_ip $http_x_real_ip;
}
client_max_body_size 128m;
large_client_header_buffers 8 64k;
charset utf-8;
location / {
proxy_set_header X-Real-IP $my_real_ip;
proxy_set_header Host $host;
proxy_read_timeout 120s;
proxy_pass http://test;
proxy_next_upstream error;
error_page 502 503 504 =503 /503.json;
}
location = /metrics {
deny all;
}
include /etc/nginx/conf.d/error-handling.conf;
}
Конфигурация апстримов используемых этим сайтом:
upstream test {
server host01.az1.local:11111 max_fails=3 fail_timeout=10s backup;
server host01.az1.local:11112 max_fails=3 fail_timeout=10s backup;
server host02.az1.local:11111 max_fails=3 fail_timeout=10s backup;
server host02.az1.local:11112 max_fails=3 fail_timeout=10s backup;
server host03.az1.local:11111 max_fails=3 fail_timeout=10s backup;
server host03.az1.local:11112 max_fails=3 fail_timeout=10s backup;
server host04.az1.local:11111 max_fails=3 fail_timeout=10s backup;
server host04.az1.local:11112 max_fails=3 fail_timeout=10s backup;
server host05.az1.local:11111 max_fails=3 fail_timeout=10s backup;
server host05.az1.local:11112 max_fails=3 fail_timeout=10s backup;
server host06.az1.local:11111 max_fails=3 fail_timeout=10s backup;
server host06.az1.local:11112 max_fails=3 fail_timeout=10s backup;
server host01.az2.local:11111 max_fails=3 fail_timeout=10s backup;
server host01.az2.local:11112 max_fails=3 fail_timeout=10s backup;
server host02.az2.local:11111 max_fails=3 fail_timeout=10s backup;
server host02.az2.local:11112 max_fails=3 fail_timeout=10s backup;
server host03.az2.local:11111 max_fails=3 fail_timeout=10s backup;
server host03.az2.local:11112 max_fails=3 fail_timeout=10s backup;
server host04.az2.local:11111 max_fails=3 fail_timeout=10s backup;
server host04.az2.local:11112 max_fails=3 fail_timeout=10s backup;
server host05.az2.local:11111 max_fails=3 fail_timeout=10s backup;
server host05.az2.local:11112 max_fails=3 fail_timeout=10s backup;
server host06.az2.local:11111 max_fails=3 fail_timeout=10s backup;
server host06.az2.local:11112 max_fails=3 fail_timeout=10s backup;
server host01.az3.local:11111 max_fails=3 fail_timeout=10s;
server host01.az3.local:11112 max_fails=3 fail_timeout=10s;
server host02.az3.local:11111 max_fails=3 fail_timeout=10s;
server host02.az3.local:11112 max_fails=3 fail_timeout=10s;
server host03.az3.local:11111 max_fails=3 fail_timeout=10s;
server host03.az3.local:11112 max_fails=3 fail_timeout=10s;
server host04.az3.local:11111 max_fails=3 fail_timeout=10s;
server host04.az3.local:11112 max_fails=3 fail_timeout=10s;
server host05.az3.local:11111 max_fails=3 fail_timeout=10s;
server host05.az3.local:11112 max_fails=3 fail_timeout=10s;
server host06.az3.local:11111 max_fails=3 fail_timeout=10s;
server host06.az3.local:11112 max_fails=3 fail_timeout=10s;
server host01.az4.local:11111 max_fails=3 fail_timeout=10s;
server host01.az4.local:11112 max_fails=3 fail_timeout=10s;
server host02.az4.local:11111 max_fails=3 fail_timeout=10s;
server host02.az4.local:11112 max_fails=3 fail_timeout=10s;
server host03.az4.local:11111 max_fails=3 fail_timeout=10s;
server host03.az4.local:11112 max_fails=3 fail_timeout=10s;
server host04.az4.local:11111 max_fails=3 fail_timeout=10s;
server host04.az4.local:11112 max_fails=3 fail_timeout=10s;
server host05.az4.local:11111 max_fails=3 fail_timeout=10s;
server host05.az4.local:11112 max_fails=3 fail_timeout=10s;
server host06.az4.local:11111 max_fails=3 fail_timeout=10s;
server host06.az4.local:11112 max_fails=3 fail_timeout=10s;
zone test 64k;
}
Обе системы на базе Debian 10, количество ОЗУ одинаковое - 8Гб, и nginx и angie устанавливались из официальных репозиториев, оба используют модули - vts, geoip (под анжи скомпилированы отдельно).
Так же хост с angie не находится под нагрузкой, трафик на него не идёт, на хост с nginx - идёт постоянный трафик
Если без сторонних модулей проверить, изменение зоны на 2k по прежнему не выдает ошибки при angie -t? Команда angie -T при этом выдает конфиг, в котором зона 2k? Как убеждаетесь в том, что reload проходит успешно?
Да, заметил ошибку в проверке конфига.
При выполнении angie -t или angie -T он считывает конфиг по пути, который указан при сборке приложения, а поскольку мы его не собирали, а скачивали с репозиториев, то по дефолту angie считает конфигурационным файлом - /etc/angie/angie.conf который проходит проверку без проблем. У нас же конфигурационный файл - /etc/nginx/nginx.conf поскольку полностью переносили конфигурацию с действующего nginx.
Но вопрос с ошибкой аллокации памяти апстрим зон остаётся открытым.
Я почему и спросил о том, как было установлено, что reload выполнен успешно. Дело в том, что операция перезагрузки конфигурации осуществляется путем отправки сигнала, а сигналы не имеют обратной связи. Получив сигнал, процесс master перечитывает конфигурацию, создает и заполняет новые зоны разделяемой памяти. Если на данном этапе случается какая-то ошибка, то она пишется в лог и процедура на этом завершается, а рабочие процессы продолжают работать с предыдущей конфигурацией.
Таким образом, узнать успешен был reload или нет, что в nginx, что в Angie - можно только проверив error log после отправки сигнала или же убедившись, что новые рабочие процессы запустились (у рабочих процессов поменяется pid).
Да, действительно, при reload ошибки не возникает, в логе пишется ошибка
2023/07/24 17:28:12 [warn] 31600#31600: could not build optimal variables_hash, you should increase either variables_hash_max_size: 1024 or variables_hash_bucket_size: 64; ignoring variables_hash_bucket_size
При этом PID не меняется, и при angie -t действительно тестируется конфигурация по пути, указанном в процессе компиляции (скрипт configure).
Спасибо вам, что обратили внимание на проблему с возросшим потреблением памяти в upstream-зоне. У нас родилась идея, как можно уменьшить потребление и в следующей версии это будет реализовано.
При сборке по умолчанию, т.е. без флагов --without-http_api_module и --without-http_upstream_sticky_module - оно все равно будет по объективным обстоятельствам повыше, чем у nginx, не имеющего данных возможностей, но оно уменьшится примерно на 3Кб на каждый сервер по сравнению с текущим потреблением.
Если же собирать с флагами --without-http_api_module и --without-http_upstream_sticky_module, то потребление памяти в upstream-зонах и сейчас не должно быть больше, чем у nginx.