Оптимизация Gunicorn для быстрых клиентов
Возьмем за пример стек 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, надеюсь, кому-то будет полезно!