2016-06-26 1 views
3

동일한 서버에서 Django 앱과 Tornado 서비스가 함께 실행됩니다. Tornado 서비스에서 Django ORM을 사용하여 MySQL 데이터베이스에 액세스합니다. 동일한 데이터베이스가 Django 앱에서 사용됩니다.'MySQL이 사라졌습니다'Django 프로젝트 외부에서 사용되는 ORM

Django 웹 앱의 모든 페이지는 클라이언트에서 렌더링 될 때 토네이도 서비스에 영구 (WebSocket) 연결을 설정합니다. 이 서비스는 Django ORM을 사용하여 데이터를 검색하고이를 클라이언트에 반환합니다.

웹 사이트는 많이 사용되지 않으며 때로는 몇 시간 또는 하루나 이틀 정도의 후속 요청이 이어질 수 있습니다.

잠시 동안 웹 사이트가 유휴 상태가 된 후에 악명 높은 '2006 : MySQL이 사라졌습니다'라는 오류가 토네이도 서비스에서 발생합니다. 나는 파기를했는데 그 원인은 MySQL에 의해 삭제 된 것으로 보인다.

이것은 내가 당황하지만, 장고 앱이 사용하는 것과 동일한 장고 ORM을 사용하고 있지만 장고 앱 자체는 결코이 오류를 발생시키지 않습니다. 또한 장고 ORM이이 오류가 발생하면 장고 ORM이 자동으로 다시 연결된다는 것을 이해합니다. 장고 ORM은 장고 앱에서이 오류가 표시되지 않는 이유를 설명합니다. 그럼 왜 토네이도에서 나 한테 일어난거야?

현재 나와있는 토네이도 인스턴스를 다시 살아나게하는 유일한 방법은 그것을 실행하는 gunicorn 프로세스를 다시 시작하는 것입니다. 다시 시작한 후 토네이도는 몇 시간 동안 그대로 둘 때까지 딸꾹질없이 작동합니다.

나는 이것을 읽었습니다 : https://code.djangoproject.com/ticket/21597#comment:29 그리고 StackOverflow에서 비슷한 문제에 대한 답을 얻었지만, MySQL에서 시간 초과가 증가하면 문제가 해결되지 않는다고 생각합니다. (어쨌든, 내 wait_timeout은 합리적으로 큰 값인 28800으로 설정되어 있습니다. 또 다른 참고로, max_allowed_packet16777216으로 설정되어 있으며, 실패한 전화는 다음과 같으므로 여기에서 문제가되지는 않습니다. 기본적으로 데이터베이스에서 세션 개체를 검색하는 것입니다.) 위의 링크에서 Django 핵심 개발자 중 한 사람이 제안한 또 다른 솔루션은 명시 적으로 연결을 닫는 것입니다. 프로그램이 유휴 상태 일 것으로 알 때 from django.db import connection; connection.close()오랜 시간. 분명히 고객이 페이지를 얼마나 자주 요청하는지 예측할 수 없기 때문에 실제로 이것을 알지 못합니다. 요청이 처리 된 후 연결을 끊으면 나에게 잔인한 것처럼 보입니다. 다른 방법이 없다면, 당연히해야 겠지만 장고가 투명하게 다시 연결되어야한다고 생각하기 때문에 여기에 뭔가있는 것 같습니다 (사실은 어딘가에 있지만 실제로는 그렇지 않습니다.)

내 주요 질문은 연결을 닫아야하는 경우 내 Django 응용 프로그램이 제대로 된 것처럼 보이는 이유는 무엇입니까? 난 장고 애플 리케이션의 모든 연결을 종료 아니에요, 그럼에도 같은 오류가 발생하지 않습니다. 닫는 연결이 필요하지 않고 Django에 의해 자동으로 수행되는 경우, 왜 Tornado 서비스에서 사용되는 Django ORM이이 오류를 던집니까?

참고로이 코드는 Tornado 앱에서이 오류를 일으키는 코드입니다.

전과합니다 ( request_started request_finished과 신호를 통해) 각 요청 후
def get_django_session(handler): 
    if not hasattr(handler, '_session'): 
     engine = importlib.import_module(
       django.conf.settings.SESSION_ENGINE) 
     session_key = handler.get_cookie(django.conf.settings.SESSION_COOKIE_NAME) 
     handler._session = engine.SessionStore(session_key) 
    return handler._session 


def get_current_user(handler): 
    # get_user needs a django request object, but only looks at the session 
    class Dummy(object): 
     pass 

    django_request = Dummy() 
    django_request.session = get_django_session(handler) 
    user = django.contrib.auth.get_user(django_request) # 2006: MySQL has gone away 
    if user.is_authenticated(): 
     return user 
    else: 
     return None 

답변

2

장고 각 연결을 테스트하여 그것이 불가능하다면 그것을 폐쇄하는 close_old_connections() 부른다. 이 메서드는 연결하기 전후에 호출 할 수 있습니다. 이렇게하면 여전히 사용할 수있는 연결이 닫히지 않으므로 토네이도에서 작업 할 때마다 새 연결을 할 수 없습니다.

+2

감사합니다. 이 문제를 확대하기 위해 https://github.com/django/django/blob/ecb59cc6579402b68ddfd4499bf30edacf5963be/django/db/__init__.py (65 ~ 66 행)에서 발생합니다. 또한, Django **는 ** https://docs.djangoproject.com/en/1.9/ref/databases/에서 설명한대로 투명하게 다시 연결합니다 **. Django가 CONN_MAX_AGE 매개 변수에 정의 된대로 특정 시간 간격이 경과하지 않으면 명시 적으로이를 수행하지 못하게 할 수도 있습니다. – hazelsparrow

관련 문제