Оптимизация Gunicorn для быстрых клиентов

02e9d5a7e67fba2470619fd8852c71a0

Возьмем за пример стек Nginx + Gunicorn + Django.
Бывает, что при наплыве трафика, Nginx отвечает ошибкой 5хх, а в логе Django ошибок нет.

Вы также можете увидеть, что Nginx говорит:»not enough workers». Это фиксится очень просто и уже есть довольно старая статья на Хабре, которая всё ещё актуальна: Ускоряем Nginx за 5 минут / Хабр (habr.com).
Единственное, что в новых версиях worker_processes лучше оставить auto.

Но Вы также можете всё ещё видеть upstream response error (timedout).
В таком случае мы обращаем внимание на Gunicorn.
Есть разные виды воркеров: Sync, Async, Gthread, Tornado, AsyncIO.

Самая распространённая конфигурация из мануалов по настройке:
gunicorn --workers 3 wsgi:app

В данном случае используются Sync воркеры, для нашего примера, а также для большинства это наиболее подходящий и универсальный вариант.

Какое количество воркеров оптимально?
Считается формулой: (Количество ядер процессора)*2+1

Итого, конфигурация выше подходит для серверов с одним ядром, если ядер больше, то можно смело увеличивать количество воркеров по формуле, но если нет, увеличение количества воркеров приведет к принудительной перезагрузке Gunicorn'a системой, т.к. тот начнет утилизировать весь процессор:
gunicorn.service: A process of this unit has been killed by the OOM killer

То есть, для сервера с 2 ядрами, лучшая конфигурация будет такая:
gunicorn --workers 5 wsgi:app

А также, у Sync воркеров есть Gthread класс:
gunicorn --workers 5 --threads 2 wsgi:app
Указывая параметр тредов, воркеры автоматически становятся класса Gthread.

Треды помогут увеличить производительность, если количество воркеров уже не увеличить.
Такая настройка подходит для не слишком требовательных к CPU, быстрых запросов, I/O операций, SQL. В общем и целом, использование тредов помогает уменьшить утилизацию памяти Gunicorn'ом.

Такая вот небольшая шпаргалка по оптимизации Gunicorn, надеюсь, кому-то будет полезно!

© Habrahabr.ru