Вопрос или проблема
У меня есть кастомное приложение на Django, которое становится неотзывчивым примерно после каждых 5000 запросов. В логах apache я вижу следующее:
Apr 13 11:45:07 www3 apache2[27590]: **успешный рендер вида здесь**
...
Apr 13 11:47:11 www3 apache2[24032]: [ошибка] сервер находится в пределах MinSpareThreads MaxClients, рассмотрите возможность увеличения настройки MaxClients
Apr 13 11:47:43 www3 apache2[24032]: [ошибка] сервер достиг настройки MaxClients, рассмотрите возможность увеличения настройки MaxClients
...
Apr 13 11:50:34 www3 apache2[27617]: [ошибка] [клиент 10.177.0.204] Скрипт завершился с таймаутом до возврата заголовков: django.wsgi
(повторяется 100 раз, точно)
Я полагаю, что я использую WSGI 2.6 (/usr/lib/apache2/modules/mod_wsgi.so-2.6) со следующей конфигурацией:
конфигурация apache
WSGIDaemonProcess site-1 user=django group=django threads=50
WSGIProcessGroup site-1
WSGIScriptAlias / /somepath/django.wsgi
/somepath/django.wsgi
import os, sys
sys.path.append('/home/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Когда это происходит, я могу убить процесс wsgi, и сервер восстанавливается.
>ps aux|grep django # процесс работает от имени пользователя "django"
django 27590 5.3 17.4 908024 178760 ? Sl Apr12 76:09 /usr/sbin/apache2 -k start
>kill -9 27590
Это заставляет меня думать, что проблема является известной проблемой:
deadlock-timeout=sss (2.0+)
Определяет максимальное количество секунд,
которые могут пройти прежде, чем демон
процесс будет отключен и перезапущен
после обнаружения потенциального взаимного
блокирования (deadlock) на
GIL Python. Значение по умолчанию — 300 секунд. Эта опция
существует, чтобы бороться с проблемой
замораживания демона
процесса в результате неправильного
освобождения GIL Python модулем
C-расширения Python при выполнении
блокирующей или длительной операции.
Тем не менее, я не уверен, почему это условие не очищается автоматически. Я вижу, что тайм-аут скрипта возникает ровно через 5 минут после последнего успешного рендеринга страницы, так что тайм-аут взаимной блокировки срабатывает. Но он фактически не убивает процесс.
Правка: дополнительная информация
- версия apache 2.2, используется worker MPM
- версия wsgi 2.8
- SELinux НЕ установлен
- пакет xml используется, нечасто
- Ubuntu 10.04
Вы можете попробовать добавить лимит запросов, после которого процессы демонов будут перезагружаться (до того, как сделает это внешний процесс).
Это делается путем добавления параметра maximum-requests
для WSGIDaemonProcess
.
Смотрите https://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Defining_Process_Groups
В качестве альтернативы вы можете узнать, сколько процессов может иметь ваш пользователь ‘django’.
Вы можете это проверить, открыв оболочку от имени этого пользователя su - django -s /bin/bash
и проверив вывод команды ulimit -a
.
Ответ или решение
Проблема, с которой вы столкнулись, в значительной степени связана с ограничениями настроек Apache и модуля mod_wsgi, и она может возникать по нескольким причинам, включая недостаточный размер пула процессов, зависание запросов, а также потенциальные проблемы с блокировкой GIL в Python. Вот несколько шагов, которые могут помочь вам решить эту проблему.
1. Увеличение параметров MaxClients и Threads
В вашем случае вы видите сообщения о том, что сервер достиг максимального числа клиентов (MaxClients). Чтобы это исправить, рассмотрите возможность увеличения параметров:
-
MaxClients: Установите его в большее значение в конфигурации Apache. Например:
MaxClients 150
Проверьте соответствие этому параметру с доступной памятью и ресурсами вашего сервера.
-
Threads: Увеличьте количество потоков для вашего процесса WSGI, если ваша система поддерживает это. Вы можете изменить определение вашей
WSGIDaemonProcess
, добавив больше потоков:WSGIDaemonProcess site-1 user=django group=django threads=75
2. Параметр максимального числа запросов
Рекомендуется добавить параметр maximum-requests
в вашу конфигурацию WSGIDaemonProcess
. Это позволит ваши демоны WSGI перезапускаться после обработки определённого количества запросов, что может помочь "освободить" потенциальные проблемы с зависанием и утечкой памяти:
WSGIDaemonProcess site-1 user=django group=django threads=50 maximum-requests=1000
3. Настройка параметра deadlock-timeout
Как вы упомянули, параметр deadlock-timeout
может быть полезен, если у вас происходят зависания. Попробуйте уменьшить время, чтобы быстрее перезапускать процессы, когда выявляется потенциальная блокировка:
WSGIDaemonProcess site-1 user=django group=django threads=50 deadlock-timeout=60
4. Проверка ulimit для пользователя Django
Важно также проверить настройки ulimit для пользователя django
, чтобы убедиться, что ему разрешено достаточно процессов. Используйте следующую команду:
su - django -s /bin/bash -c "ulimit -a"
Если значение max user processes
низкое, вы можете увеличить его в файле /etc/security/limits.conf
.
5. Мониторинг и логгирование
Включите более детальное логгирование для вашего приложения Django, чтобы понимать, какие запросы могут зависать и как долго они выполняются. Обычно это можно сделать путем установки уровня логирования на DEBUG
в настройки Django.
6. Обновление модулей
Проверьте, используете ли вы актуальные версии Apache, mod_wsgi и Django. Обновление до последней стабильной версии может устранить ряд известных ошибок, связанных с производительностью и стабильностью.
Заключение
Если выполнение этих шагов не решит вашу проблему, возможно, стоит исследовать конкретные запросы к вашему Django-приложению, которые могут тормозиться или зависать. Это могут быть сложные запросы к базе данных, внешние API или длинные вычисления. Используйте профилирование производительности, чтобы выявить узкие места в вашем коде. Если после всех изменений поведение приложения не станет лучше, возможно, придется рассмотреть более масштабные архитектурные изменения, такие как переход на более высокопроизводительные серверы или использование альтернативных подходов к обработке запросов (например, с использованием Celery для долгих задач).
Если у вас останутся вопросы или проблемы, не стесняйтесь обращаться за помощью!