programing

Django, 업그레이드 후:내 SQL 서버가 사라졌습니다.

javajsp 2023. 9. 26. 22:01

Django, 업그레이드 후:내 SQL 서버가 사라졌습니다.

최근에 Django 1.4에서 Django 1.7로 업그레이드했는데 일부 스크립트에 대해 다음 오류 메시지가 계속 뜨기 때문에 때때로 다음과 같은 메시지가 나타납니다.

OperationalError: (2006, 'MySQL server has gone away')

스크립트가 매우 길거나 계속 실행 중인 작업으로, 몇 분 동안 DB와 통신하지 않는 단계가 수반되어 연결 시간이 초과됩니다.하지만 제가 업그레이드하기 전에 장고가 자동적으로 연결을 다시 설정하는 것 같았기 때문에 문제가 되지 않았습니다.이제 작업이 중단되고 중간에 실패하는 경우가 많다는 의미는 아닙니다.

무엇이 바뀌었는지 그리고 어떻게 고칠 수 있는지 아는 사람?

티켓/수정과 관련이 있습니까? https://code.djangoproject.com/ticket/21463

정말 고마워.

이러한 동작의 이유는 장고 1.6에서 도입된 데이터베이스에 대한 지속적인 연결 때문입니다.

시간 하려면 를(를) .CONN_MAX_AGE인에settings.py을 매기다wait_timeoutMySQL성()my.cnf이 경우 Django는 MySQL이 생성하는 것보다 먼저 연결을 다시 열어야 함을 감지합니다.MySQL 5.7의 기본값은 28800초입니다.

settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'CONN_MAX_AGE': 3600,
        <other params here>
    }
}

문서: https://docs.djangoproject.com/en/1.7/ref/settings/ #conn-max-age

my.cnf:

wait_timeout = 28800

문서: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_wait_timeout

가 실행 입니다.rqworker일부 사용자 작업 후 일부 데이터를 새로 고치기 위해 별도의 작업을 실행합니다.

에 .OperationalError: (2006, 'MySQL server has gone away')wait_timeout.초. CONN_MAX_AGE를 MySQL보다 wait_timeout.

제가 알기로는, 장고가 이 타임아웃까지 자동으로 연결을 확인하고 닫는다면 CONN_MAX_AGE 변경이 도움이 될 것 같습니다.그러나 Django 1.7.x는 각 요청 전후에만 확인합니다(django/db/init.py#L101-L112 참조).

장고 티켓 15119에 나와 있는 것처럼, 우리는 장고가 모든 쿼리를 실행하기 전에 연결이 살아 있는지 확인하기 위해 핑을 하고 있었음을 알 수 있습니다.이 동작은 커밋 282b2f4에서 수정되었습니다.

장고 개발자들은 https://code.djangoproject.com/ticket/21597#comment:29 에서 이와 같은 모든 질문에 대해 짧은 답변을 하나 했습니다.

rqworker프로세스는 각 새 작업에 대해 연결 자체를 검증해야 합니다.가 새 (참고: 연결을 닫으면 장고가 새 연결을 만듭니다.)

리퀘스트 를 구하고 입니다를 django.db.close_old_connections()모든 일의 전후에그리고 네.CONN_MAX_AGE MySQL.wait_timeout, 왜냐하면 장고는 확인을 안하기 때문입니다.MySQL server has gone away인에django.db.close_old_connections()방법.

장고 1.9에서: 유닉스 화면에서 진행 중인 장고 셸을 48시간 이상 방치했습니다.내가 그 곳으로 돌아와서 달려갔을 때<some_model>.objects.filter던졌습니다.OperationalError: (2006, 'MySQL server has gone away')

import django.db; django.db.close_old_connections()나를 위해 속임수를 썼답니다.

에 대한 를 찾을 수 close_old_connections()1.9 장고 문서에서 하지만 여기 깃허브의 장고 코드베이스에서 구현된 직접적인 링크가 있습니다.

django 1.6에서 wait_timeout이 경과하면 (mysql의) DB 액세스로 인해 (2006년 'MySQL 서버가 사라졌습니다') 오류가 발생합니다.장고 1.5.1에서는 그렇지 않았습니다.

장고 코드를 실행하는 작업자(기어맨 사용)를 사용할 때 이 오류를 발견했습니다.

재생하는 방법:

[mysql]에서 /etc/mysql/my.cnf를 편집하여 제한 시간을 낮은 값으로 설정합니다.

wait_timeout = 10
interactive_timeout = 10

그리고나서

% python manage피조개

>>> # access DB 
>>> import django.contrib.auth.models
>>> print list(django.contrib.auth.models.User.objects.all())
>>> import time
>>> time.sleep(15)
>>> print list(django.contrib.auth.models.User.objects.all())

이제 오류를 알 수 있습니다.

웹에서 찾은 간단한 해결책은 접속 전에 django.db.close_connection()을 호출하는 것입니다.

>>> import django.db
>>> django.db.close_connection()
>>> print list(django.contrib.auth.models.User.objects.all())

일이 잘 됩니다.

저희도 눈치챘어요.위의 답변은 웹에 대해 CONN_MAX_AGE를 MySQL / MariaDB의 wait_timeout보다 작은 것으로 설정하는 것입니다.

오랫동안 실행 중인 작업의 경우에는 이 작업이 작동하지 않는 것 같습니다.대신에 우리는 오래 실행 중인 작업 중 하나가 실행될 때마다 그것을 포장하고 연결을 닫습니다.

우리는 이것을 자체 맞춤형 풀과 결합합니다.가져가든, 놔두든 - 기본적인 Django one은 통제력이 전혀 없습니다 - 우리가 제작에서 좋아했던 것이 아닙니다.서버가 너무 많은 연결로 DB를 죽이기 전에 서버를 죽일 수 있는 최대 풀을 설정했습니다.작업을 위한 장식 도구로 사용:

@close_db_connection()
def task_do_something():
    print 'Hello'


'''
Created on Dec 23, 2017

@author: Kevin
'''
from functools import wraps

def close_db_connection(ExceptionToCheck=Exception, raise_exception=False, notify=False):
    """Close the database connection when we're finished, django will have to get a new one..."""
    def deco_wrap(f):
        @wraps(f)
        def f_wrap(*args, **kwargs):
            try:
                return f(*args, **kwargs)
            except Exception as e:
                raise e
            finally:
                from django.db import connection; 
                connection.close();

        return f_wrap
    return deco_wrap

쇼트:

  1. pip install mysql_server_has_gone_away

  2. 설정.py:

DATABASES = {
    'default': {
        'ENGINE': 'mysql_server_has_gone_away'
    }
}

TL;DR

저의 경우는 장고 ORM을 사용하고 있었고, long living request(webocket)를 사용하고 있었습니다.CONN_MAX_AGE제 경우에는 통하지 않습니다.

처음에는 오류를 잡아보려고 포장지를 만들었지만 장고가 귀찮아서 어떤 물건으로 포장해야 할지 잘 모르겠습니다.그래서 프로젝트 전반에 걸쳐 이 코드를 복제하게 되었는데 그건 일종의 골칫거리였습니다.예를 에를 .User.objects.get(id=3)다를 할.do_db(User.objects.get, id=3)고 db였습니다.try: return callback(*args, **kwargs); catch e: conn.close(); callback(*args, **kwargs).

장고 백엔드를 파고들 때 이 솔루션을 연결 수준으로 마이그레이션할 수 있습니다.따라서 db로 가는 모든 쿼리는 다음과 같이 래핑됩니다.

설정.py:

DATABASES = {
    'default': {
        'ENGINE': 'lol'
    }
}

lol/base.py:

""" 
https://stackoverflow.com/a/60894948/3872976
"""

from django.db.backends.mysql import base


def check_mysql_gone_away(db_wrapper):
    def decorate(f):
        def wrapper(self, query, args=None):
            try:
                return f(self, query, args)
            except (base.Database.OperationalError, base.Database.InterfaceError) as e:
                if 'MySQL server has gone away' in str(e):
                    db_wrapper.connection.close()
                    db_wrapper.connect()
                    self.cursor = db_wrapper.connection.cursor()
                    return f(self, query, args)
                # Map some error codes to IntegrityError, since they seem to be
                # misclassified and Django would prefer the more logical place.
                if e.args[0] in self.codes_for_integrityerror:
                    raise base.utils.IntegrityError(*tuple(e.args))
                raise
        return wrapper

    return decorate


class DatabaseWrapper(base.DatabaseWrapper):

    def create_cursor(self, name=None):

        class CursorWrapper(base.CursorWrapper):

            @check_mysql_gone_away(self)
            def execute(self, query, args=None):
                return self.cursor.execute(query, args)

            @check_mysql_gone_away(self)
            def executemany(self, query, args):
                return self.cursor.executemany(query, args)

        cursor = self.connection.cursor()
        return CursorWrapper(cursor)

원자력 작동 중에 mysql 연결이 끊어지면 거래에 문제가 생길 수 있다는 점에 유의해야 합니다.하지만 불행히도 다른 방법이 없습니다.

아마도 타임아웃은 몇몇 사람들에게 문제가 될 수 있지만 매우 큰 BLOB 필드를 작성하려고 할 때 이 문제에 부딪혔습니다.mysql 구성 파일에서 허용되는 최대 패킷 크기를 늘려서 해결했습니다...

max_allowed_packet=4M

/etc/my.cnf로 변경한 후 mysql을 다시 시작하는 것을 잊지 마십시오.이 페이지는 도움이 됐습니다...

http://dev.mysql.com/doc/refman/5.5/en/packet-too-large.html

저는 제 해결책이 어디에 있는지 같은 문제에 직면해 있었습니다.저는 장고에 처음 와서 이미 늦었지만 해결책을 올립니다.누군가에게 도움이 될지도 모릅니다.

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'your_dabase',
    'USER': 'your_user',
    'PASSWORD': 'your_password',
    'HOST': 'your_host',
    'PORT': 'your_port',
    'CONN_MAX_AGE': 290,
},
'OPTIONS': {
    'timeout':20,
    } 

}

CONN_MAX_AGEOPTIONS를 추가했고 현재 완벽하게 작동하고 있습니다.

이것이 오래된 질문이라는 것을 알고 있지만, 제 경우의 해결책은 현재의 어떤 대답에도 없었습니다.

제 문제의 근원은 서버 쪽에 있었습니다.서버 시간 초과 설정 확인(사용)show global variables like '%timeout') 제가 알게 된 것은wait_timeout변수가 120초로 설정되어 있으므로 데이터를 검색하거나 저장하려고 할 때 이 시간이 걸리는 작업은 '서버가 사라졌습니다'라는 예외가 발생합니다.추가하기CONN_MAX_AGE아무런 차이가 없었습니다.

솔루션 #1 - 서버의 wait_timeout 설정 변경(권한이 있는 경우)

사용하다set global wait_timeout=1*60*60시간은 초 단위로 제공됩니다.

솔루션 #2 - db 유휴 시간 후 새 연결 강제 수행

Django 보기/태스크에서:

from django.db import connection
from django.db.utils import OperationalError

cursor = connection.cursor()
cursor.execute('SELECT 1')  # <-- no issues here

# time consuming code...

try:
    cursor.execute('SELECT 1')
except OperationalError:
    connection.connect()
    cursor = connection.cursor()
    cursor.execute('SELECT 1')

관찰:
이것은 ORM 요청에도 적용되어야 합니다.
장고 버전 3.1.6

고치다OperationalError: (2006, 'MySQL server has gone away')위해서Django >= 4.1장고 설정을 업데이트 할 수 있습니다.

  1. 데이터베이스에 대한 영구 연결 사용 및 CONN_MAX_AGE 설정
DATABASES = {
   'default': {
      ....
      'CONN_MAX_AGE': 60,  # value must be less then your Mysql `interactive_timeout`/`wait_timeout`
}}
  1. 영구 연결 재사용에 대해 상태 검사를 사용하도록 설정하고 CONN_HEalth_CHECKs를 설정합니다.
DATABASES = {
   'default': {
      ....
      'CONN_HEALTH_CHECKS': True,
}}

각 db 요청에 대한 결과Djangos 를 확인하고, ping에서 지"s _usable)면 Django다가 됩니다.

언급URL : https://stackoverflow.com/questions/26958592/django-after-upgrade-mysql-server-has-gone-away