Как обнаружить тупики в приложениях django (и избавиться от них) - PullRequest
1 голос
/ 10 января 2012

Я поддерживаю проект django, который перестает отвечать на регулярной основе. До сих пор я справлялся с ситуацией, постоянно отслеживая приложение и перезапуская apache при необходимости.

Не отвечает как? Это означает, что apache больше не отвечает на любой запрос.

Окружающая среда:

  • ОС: Debian Squeeze 64bit
  • Веб-сервер: Apache 2.2.16 mod_wsgi (mod_python находился в разработке около года)
  • Django: 1.3.1 (и все основные версии, начиная с 1.0)
  • Python: 2.6.6 + virtualenv (с использованием дистрибутива, no-site-packages, несколько различных установок были в производстве ранее)
  • База данных: psycopg2 2.3.2
  • База данных: PostgreSQL 9.0 (в прошлом использовалась версия 8.3)
  • Пул соединений: pgbouncer (проблемы остаются, если вы не используете bouncer)
  • Обратный прокси: nginx 1.0.11

Что я могу сделать, чтобы приблизиться к корню ошибки? (Я не могу не предоставить исходный код - фрагменты здесь и там возможны, хотя) Я так долго охотился за этой проблемой, что невозможно перечислить все, что я пробовал. Я пытался избавиться от любой «магии», о которой мог подумать. Несколько частей приложения были переписаны с момента возникновения проблемы.

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

Ответы [ 2 ]

2 голосов
/ 11 января 2012

В конечном итоге вам нужны новые функции, которые были добавлены в mod_wsgi 4.0.Это позволит в режиме демона лучше контролировать автоматический перезапуск при блокировке запросов.При перезапуске после заблокированного условия mod_wsgi попытается сбросить трассировки стека Python для того, что каждый из потоков запросов Python делал в то время, чтобы вы могли понять, почему они заблокированы.

Предложите вам решить проблему вСписок рассылки mod_wsgi и может объяснить новые функции более подробно, если это будет необходимо.Ранее сообщали об этом по адресу:

http://groups.google.com/group/modwsgi/msg/2a968d820e18e97d

Код mod_wsgi 4.0 доступен только из репозитория исходного кода в настоящее время.Текущая голова ствола считается стабильной.

1 голос
/ 04 марта 2013

Вы можете быть укушены следующей ошибкой django [1] (которая еще не исправлена ​​в ветке 1.4)

обходной путь: вручную примените fix к источникам django или используйтепотокобезопасная оболочка вокруг модуля wsgi, как показано ниже (мы используем это в производственных системах)

from __future__ import with_statement
from  django.core.handlers.wsgi import WSGIHandler as DjangoWSGIHandler

from threading import Lock

__copyright__ = "Jibe"

class WSGIHandler(DjangoWSGIHandler):
    """
    This provides a threadsafe drop-in replacement of django's WSGIHandler.

    Initialisation of django via a multithreaded wsgi handler is not safe.
    It is vulnerable to a A-B B-A deadlock.

When two threads bootstrap django via different urls you have a change to hit 
the following deadlock.

  thread 1                                               thread  2
    view A                                                  view B
     import file foo            import lock foo               import file bar  import lock bar
           bootstrap django     lock AppCache.write_lock
                import file bar import lock bar  <-- blocks
                                                                 bootstrap django    lock AppCache.write_lock  <----- deadlock

workaround for an AB BA deadlock:  wrap it in a lock C.

        lock C                      lock C
            lock A                      lock B
            lock B                      lock A
            release B                   release A
            release A                   release A
        release C                   release C          

    Thats exactly what this class does,  but... only for the first few calls.  
    After that we remove the lock C.  as the AppCache.write_lock is only held when django is booted. 

    If we would not remove the lock C after the first few calls, that would make the whole app single threaded again. 

    Usage:    
        in your wsgi file replace   the following lines 
                import django.core.handlers.wsgi.WSGIHandler  
                application = django.core.handlers.wsgi.WSGIHandler 
        by 
                import threadsafe_wsgi 
                application = threadsafe_wsgi.WSGIHandler 


    FAQ: 
        Q: why would you want threading in the first place ?                 
        A: to reduce memory. Big apps can consume hundeds of megabytes each.  adding processes is then much more expensive than threads. 
           that memory is better spend caching, when threads are almost free. 

        Q: this deadlock, it looks far-fetched, is this real ? 
        A: yes we had this problem on production machines. 
    """ 
    __initLock = Lock()  # lock C 
    __initialized = 0 

    def __call__(self, environ, start_response): 
        # the first calls (4) we squeeze everybody through lock C 
        # this basically serializes all threads 
        MIN_INIT_CALLS = 4 
        if self.__initialized < MIN_INIT_CALLS: 
            with self.__initLock: 
                ret = DjangoWSGIHandler.__call__(self, environ, start_response) 
                self.__initialized += 1 
                return ret 
        else: 
            # we are safely bootrapped, skip lock C 
            # now we are running multi-threaded again 
            return  DjangoWSGIHandler.__call__(self, environ, start_response)

и в вашем wsgi.py используйте следующий код

from threadsafe_wsgi.handlers import WSGIHandler
django_handler = WSGIHandler()

[1]https://code.djangoproject.com/ticket/18251

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...