Вопрос или проблема
У меня есть настройка nginx / gunicorn / django, следующая:
Nginx
server {
listen 80;
server_name myserver.com;
root /www/python/apps/pyapp/;
access_log /var/log/nginx/myserver.com.access.log;
error_log /var/log/nginx/myserver.com.error.log;
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 10;
proxy_read_timeout 10;
proxy_pass http://localhost:8081/;
}
}
Мой сценарий upstart для gunicorn
description "pyapp"
start on [2345]
stop on [06]
respawn
# запуск из пути виртуального окружения
chdir /www/python/apps/pyapp/
exec /usr/bin/gunicorn -w 11 -b 0.0.0.0:8081 --error-logfile=/var/log/nginx/pyapp.log wsgi:application
Сервер работает хорошо, запросы обрабатываются довольно нормально. Однако, когда я начинаю направлять трафик к этой настройке с моего старого сервера, страницы начинают выдавать ошибки 504 gateway timeout.
Запросы лишь извлекают данные из базы данных и рендерят их с использованием django-rest-framework. Смотрев на список процессов MySQL, не похоже, что там есть зависшие запросы. Это довольно странно.
Есть какие-нибудь рекомендации?
Во-первых, вы можете попробовать, как работает ваш бэкенд (django/gunicorn) без nginx впереди. ab (apache benchmark) — это простой инструмент для этой задачи.
Вы можете запустить его напрямую с сервера, или если ваш порт 8081 не заблокирован на каких-либо машинах:
ab -c 50 -n 500 http://localhost/path-xyz/
(ab доступен через пакет apache2-utils, по крайней мере, на системах на основе Debian) -c означает «конкуренция», -n — количество запросов.
Если бэкенд является узким местом, и вы все равно используете nginx, возможно, имеет смысл сделать кэширование (не знаю ваше приложение, но, возможно…). Если ваш API предоставляет данные, которые часто изменяются, вы можете установить действительно короткое время кэширования. (от 1 до 10 секунд) — так что, если у вас, например, 100 запросов в секунду, только один из них должен попадать в бэкенд, остальные получат кэшированный ответ.
Для прокси/кэша nginx смотрите, например, здесь.
Ответ или решение
504 Gateway Timeout при использовании Nginx, Gunicorn и Django может стать настоящей головной болью для разработчиков и системных администраторов. Эта ошибка обычно означает, что сервер, к которому Nginx пытается обратиться (в вашем случае Gunicorn), не отвечает в течение установленного времени ожидания. Давайте разберёмся с вашей конфигурацией и потенциальными источниками проблемы.
Анализ конфигурации
-
Nginx:
Ваш файл конфигурации Nginx выглядит вполне стандартно, но обратите внимание на настройки тайм-аутов. В текущем состоянии ваши параметры
proxy_connect_timeout
иproxy_read_timeout
установлены на 10 секунд. Если Gunicorn или Django будут задерживаться более этого времени, вы получите 504 ошибку. В таких случаях рекомендуется увеличить эти значения.proxy_connect_timeout 30; proxy_read_timeout 30;
Это даст запросам больше времени для обработки.
-
Gunicorn:
У вас установлен 11 воркеров (параметр -w 11). Это вполне может быть недостаточно, особенно если нагрузка возрастает, и запросы требуют значительных ресурсов для работы с базой данных. Увеличение количества воркеров может помочь, особенно если у вас много однотипных запросов.
Вы можете попробовать увеличить количество воркеров, основываясь на количестве CPU ядер. Рекомендуется использовать следующую формулу:
(2 x число_ядер) + 1
-
Проверка работы без Nginx:
Как вы уже упомянули, выполнение бенчмарков непосредственно на Gunicorn с помощью Apache Benchmark (ab) — это отличная идея. Это поможет выяснить, является ли проблема связанной с Nginx или Gunicorn. Выполнив следующую команду, вы сможете проверить производительность приложения:
ab -c 50 -n 500 http://localhost:8081/path-xyz/
Дополнительные рекомендации
-
Мониторинг производительности:
Используйте инструменты для мониторинга производительности, такие как New Relic или Prometheus, чтобы следить за состоянием ваших приложений и серверов. Это поможет выявить узкие места. -
Настройка кэширования:
Вы отметили, что запросы только извлекают данные из базы данных. Вы можете рассмотреть возможность использования кэширования в Django (например, с помощью Redis или Memcached) для частых запросов. Это значительно снизит нагрузку на базу данных и улучшит общую производительность. -
Проверьте базу данных:
Хотя вы упомянули, что не увидели зависших запросов в MySQL, стоит убедиться, что у вас достаточно ресурсов для обработки запросов. Используйте команды, такие какSHOW PROCESSLIST
, чтобы внимательно просмотреть экспериментальные запросы. -
Логи:
Просмотрите логи как Nginx, так и Gunicorn. В логах ошибок вы можете найти подсказки о нестандартных ситуациях или ошибках, которые могли привести к тайм-аутам. -
Настройка серверного окружения:
Убедитесь, что система (ОС, среда выполнения и зависимости) обновлена и работает оптимально. Иногда проблемы могут быть связаны с устаревшими библиотеками или зависимостями.
Заключение
Ошибка 504 Gateway Timeout указывает на проблемы с задержкой взаимодействий между Nginx и Gunicorn. Увеличение времени ожидания, увеличение числа воркеров, оптимизация работы с базой данных и кэширование — это шаги, которые могут помочь в решении вашей проблемы. Рекомендуется проводить регулярный мониторинг и тестирование производительности вашего приложения для своевременного выявления и устранения узких мест.