Re: nginx 1.18.0 ест всю память и swap на Ubuntu Server 20.04.1 LTS

Maxim Dounin mdounin на mdounin.ru
Пн Авг 31 16:41:18 UTC 2020


Hello!

On Mon, Aug 31, 2020 at 04:48:36PM +0300, Alexey Galygin wrote:

> мы запросили у организации, которая занимается DDoS Protection
> список всех запросов за интервал теста
> 
> пытаемся по этим ссылкам ходить скриптом…
> 
> на штатный resize пришлось не более 800 запросов за всё время эксперимента, вряд ли бы это забило всю память
> (файлики jpg они маленькие, ну допустим текло по 1 Мб на запрос, ну утёк бы 1 Гб за 5 минут, а не 300…)
> 
> ну и точно такой же nginx 1.18.0 на эталонном сервере так не утекает
> 
> изменилось в стенде только — Ubuntu — была 16.04 стала 20.04 (тут я подозреваю, сменился аллокатор памяти, что-то с FS подкрутили, может дескрипторы если не утекают, то кэш избыточный накапливается в ОЗУ)
> память — было 192 — стало 256
> FS как была ext4 так и осталась ext4…
> ЦОД — было нормальное железо — стала платформа VMWare Cloud Director… на вид работает даже шустрее

Это называется "сменилось примерно всё".
Я бы начал с простого:

0. Внимательно изучил конфигурацию.

Простая оценка максимального потребления памяти рабочим процессом: 
worker_connections * (сумма всех буферов в конфиге).  Стандартные 
размеры буферов невелики, и сумму всех можно смело считать как 
"меньше одного мегабайта", если в конфиге задано что-то иное - 
соответственно прибавлять.  Относительно большие размерыы буферов 
встречаются только в image-фильтре (image_filter_buffer 1m) и mp4 
(mp4_max_buffer_size 10m).

Нюанс: простая оценка не работает, если используются подзапросы 
(SSI, cache background update, и так далее - каждый подзапрос 
может иметь свои буфера, соответственно надо умножать на 
количество подзапросов в одном соединении) и/или HTTP/2 (умножать 
на http2_max_concurrent_streams + http2_max_concurrent_pushes).

Если результат больше или сравним с наблюдаемым потреблением 
памяти - то чинить конфигурацию, если заметно больше - то искать 
дальше.

Если я правильно помню приведённые фрагменты конфига, то там 4096 
worker_connections, буферов мегабайта на 2 минимум, используется 
background update.  Если HTTP/2 не используется, то общее 
потребление памяти в пределе будет 4096 * 2m * 2 == 16 гигабайт.  
Это меньше, чем наблюдается, но не сильно.  Что уже наводит на 
всяческие мысли.  Если же ещё и HTTP/2 используется - то один 
рабочий процесс может занимать до пары терабайт, что явно не 
соответствует возможностям машины.

То есть в принципе все наблюдаемые эффекты могут просто 
объясняться конфигурацией и характером нагрузки, без всяких 
утечек.  Можно попробовать отключить HTTP/2, если вдруг 
используется, и/или покрутить размеры буферов вниз.  Ну и 
количество рабочих процессов тоже.

Отдельный вопрос - почему не наблюдаются такие же или близкие 
размеры рабочих процессов на старом сервере.  Если конфигурации 
полностью совпадают - возможно, причина в несколько другом 
характере нагрузки, в частности - из-за смены ядра и платформы.  
Меня, в частности, сильно смущает, что все рабочие процессы в 
состоянии "D", смотреть стоит на дисковую подсистему.

1. Если есть какие-то сторонние модули - исключил их из конфига 
(или сборки, если они собраны статически), и убедился, что 
проблема воспроизводится.  Если модули очень нужны - то можно 
попробовать переписать конфиг так, чтобы вынести их в отдельный 
инстанс nginx'а.

2. Если в конфиге используется скриптовый код - perl, njs, 
whatever - то этот код может потреблять произвольный объём памяти, 
даже если код кажется простым.  Опять же, лучше всего попробовать 
воспроизвести проблему без этого кода.

Ну и логи таки имеет смысл почитать, дабы точно понимать, что 
происходит, а не строить предположения.

[...]

-- 
Maxim Dounin
http://mdounin.ru/


Подробная информация о списке рассылки nginx-ru