programing

Python and Django Operational Error (2006, 'MySQL 서버가 사라졌습니다')

subpage 2023. 9. 16. 09:04
반응형

Python and Django Operational Error (2006, 'MySQL 서버가 사라졌습니다')

원본:나는 최근에 내 오래된 코드 중 일부에서 MySQL Operational Errors를 받기 시작했는데 문제를 추적할 수 없는 것 같습니다.이전에 작동이 됐기 때문에 소프트웨어 업데이트 때문에 뭔가 고장이 난 것이 아닐까 생각했습니다.저는 nginx와 함께 python 2.7과 django runfcgi를 사용하고 있습니다.제 원래 코드는 다음과 같습니다.

views.py

DBNAME = "test"
DBIP = "localhost"
DBUSER = "django"
DBPASS = "password"
db = MySQLdb.connect(DBIP,DBUSER,DBPASS,DBNAME)
cursor = db.cursor()

def list(request):
    statement = "SELECT item from table where selected = 1"
    cursor.execute(statement)
    results = cursor.fetchall()

다음을 시도해 보았지만 여전히 작동하지 않습니다.

views.py

class DB:
    conn = None
    DBNAME = "test"
    DBIP = "localhost"
    DBUSER = "django"
    DBPASS = "password"
def connect(self):
    self.conn = MySQLdb.connect(DBIP,DBUSER,DBPASS,DBNAME)
def cursor(self):
    try:
        return self.conn.cursor()
    except (AttributeError, MySQLdb.OperationalError):
        self.connect()
        return self.conn.cursor()

db = DB()
cursor = db.cursor()

def list(request):
    cursor = db.cursor()
    statement = "SELECT item from table where selected = 1"
    cursor.execute(statement)
    results = cursor.fetchall()

현재 저의 유일한 해결책은MySQLdb.connect()sql을 하는 각 에서.그리고 장고 제품을 사용할 때도 눈에 띄었습니다.manage.py runserver 오류를 동안에는 이 nginx 는 를 입니다 를 입니다 를 .내가 연결을 끊는 것은 아닌지 의심이 됩니다.list()서버를 시작한 후 몇 초 안에 호출됩니다.이 문제를 해결할 수 있는 소프트웨어 업데이트가 있습니까?

편집: 최근에 함수를 데몬화하기 위해 미들웨어를 작성했고 이것이 문제의 원인이라는 것을 깨달았습니다.하지만, 그 이유를 알 수가 없습니다.여기 미들웨어의 코드가 있습니다.

def process_request_handler(sender, **kwargs):
    t = threading.Thread(target=dispatch.execute,
        args=[kwargs['nodes'],kwargs['callback']],
        kwargs={})
    t.setDaemon(True)
    t.start()
    return
process_request.connect(process_request_handler)

때때로 "OperationError: (2006년 'MySQL Server has away')"라고 표시되는 경우가 있는데, 이는 너무 큰 쿼리를 실행하기 때문입니다.예를 들어 세션을 MySQL에 저장할 때 세션에 정말 큰 것을 넣으려고 하는 경우 이러한 현상이 발생할 수 있습니다.문제를 해결하려면 MySQL의 max_allowed_packet 설정 값을 늘려야 합니다.

기본값은 1048576입니다.

기본값의 현재 값을 보고 다음 SQL을 실행합니다.

select @@max_allowed_packet;

새 값을 임시로 설정하려면 다음 SQL을 실행합니다.

set global max_allowed_packet=10485760;

문제를 보다 영구적으로 해결하려면 최소한 다음을 포함하여 /etc/my.cnf 파일을 만듭니다.

[mysqld]
max_allowed_packet = 16M

/etc/my.cnf를 편집한 후 방법을 모르면 MySQL을 다시 시작해야 합니다.

MySQL 문서에 따르면 클라이언트가 서버에 질문을 보낼 수 없을 때 오류 메시지가 표시됩니다. 아마도 서버 자체가 연결을 닫았기 때문일 것입니다.가장 일반적인 경우, 서버는 8시간(기본값) 후 유휴 연결을 닫습니다.이것은 서버측에서 구성할 수 있습니다.

MySQL 설명서는 다른 여러 가지 가능한 원인을 제공하며, 이러한 원인이 사용자의 상황에 적합한지 살펴볼 가치가 있습니다.

를 부르는 것의 connect()(필요 없이 새로운 연결을 만들 수도 있는) 모든 기능에서 사용하여 조사하는 것이 될 것입니다.ping()연결 개체에 대한 메서드입니다. 자동 재연결을 시도하는 옵션을 사용하여 연결을 테스트합니다.나는 그것을 위한 괜찮은 문서를 찾기 위해 애를 썼습니다.ping()method on online, 하지만 이 질문에 대한 답이 도움이 될 수 있습니다.

참고로 트랜잭션을 처리할 때 자동으로 재연결하면 재연결이 암묵적인 롤백을 일으키는 것처럼 보이기 때문에 위험할 수 있습니다(자동 재연결이 MySQLDB 구현의 기능이 아닌 주된 이유인 것으로 보입니다).

이는 기본 스레드에서 자식 스레드에서 DB 연결이 복사되기 때문일 수 있습니다.python의 멀티프로세싱 라이브러리를 사용하여 다른 프로세스를 생성할 때 동일한 오류가 발생했습니다.연결 개체는 포크하는 동안 프로세스 간에 복사되며 하위 스레드에서 DB 호출을 할 때 MySQL OperationalErrors로 연결됩니다.

이를 해결하기 위한 좋은 참고 자료는 다음과 같습니다.장고 다중 처리 및 데이터베이스 연결

저는 디버그 모드에서 이런 일이 일어났습니다.

그래서 디버그 모드에서 Persistent connections를 시도했는데 링크를 확인해보세요.Django - Documentation - Databases - Persistent Connections.

설정에서:

'default': {
       'ENGINE': 'django.db.backends.mysql',
       'NAME': 'dbname',
       'USER': 'root',
       'PASSWORD': 'root',
       'HOST': 'localhost',
       'PORT': '3306',
       'CONN_MAX_AGE': None
    },

한 스레드에서 mysql 연결 개체를 생성한 후 다른 스레드에서 사용할 수 있는지 확인합니다.

금지되어 있는 경우에는 실밥을 사용합니다.스레드당 연결에 대한 로컬:

class Db(threading.local):
    """ thread-local db object """
    con = None

    def __init__(self, ...options...):
        super(Db, self).__init__()
        self.con = MySQLdb.connect(...options...)

db1 = Db(...)


def test():
    """safe to run from any thread"""
    cursor = db.con.cursor()
    cursor.execute(...)

이 오류는 MySQL이 연결이 끊기는 이유를 보고하지 않고 그냥 사라지기 때문에 알 수 없습니다.

이런 단절에는 여러 가지 원인이 있는 것 같습니다.방금 발견한 것 중 하나는 질의 문자열이 너무 크면 서버가 연결이 끊어진다는 것입니다.이것은 아마도 그것과 관련이 있을 것입니다.max_allowed_packets세팅

저도 이 문제로 힘들어하고 있습니다.저는 제 sql 서버에서 시간 초과를 늘린다는 생각이 마음에 들지 않습니다.동과 자동 CONNECTION_MAX_AGE말씀하신 것처럼 작동하지도 않습니다.도 이렇게 .

def do_db( callback, *arg, **args):
    try:
        return callback(*arg, **args)
    except (OperationalError, InterfaceError) as e:  # Connection has gone away, fiter it with message or error code if you could catch another errors
        connection.close()
        return callback(*arg, **args)

do_db(User.objects.get, id=123)  # instead of User.objects.get(id=123)

보시다시피 저는 데이터베이스를 조회하기 전에 매번 ping을 하는 것보다 예외를 잡는 것을 더 선호합니다.왜냐하면 예외를 잡는 것은 드문 경우이기 때문입니다.저는 장고가 자동으로 다시 연결되기를 기대했지만 그들은 그 문제를 거절한 것 같습니다.

데이터베이스로 이동하지 않는 시간이 많이 걸리는 작업 후 연결을 사용하려고 할 때 이 오류가 발생할 수 있습니다.연결이 한동안 사용되지 않으므로 MySQL 시간 초과가 발생하고 연결이 자동으로 삭제됩니다.

전화해 보세요.close_old_connections()연결을 사용할 수 없는 경우 새 연결이 열리도록 시간이 많이 소요되는 비DB 작업 후.주의, 사용하지 말 것close_old_connections()거래가 있는 경우.

이러한 경고와 관련하여 가장 일반적인 문제는 당신의 애플리케이션이 도달했다는 사실입니다.wait_timeoutMySQL의 값입니다.

플라스크 앱에서도 같은 문제가 있었습니다.

해결 방법은 다음과 같습니다.

$ grep timeout /etc/mysql/mysql.conf.d/mysqld.cnf 
# https://support.rackspace.com/how-to/how-to-change-the-mysql-timeout-on-a-server/
# wait = timeout for application session (tdm)
# inteactive = timeout for keyboard session (terminal)
# 7 days = 604800s / 4 hours = 14400s 
wait_timeout = 604800
interactive_timeout = 14400

관찰: MySQL 배치 모드를 통해 변수를 검색하면 값이 그대로 나타납니다.하지만 여러분이 공연을.SHOW VARIABLES LIKE 'wait%';아니면SHOW VARIABLES LIKE 'interactive%';, 에 대해 설정된 값interactive_timeout, 두 변수 모두에 나타날 것이고, 이유는 모르겠지만, 사실은 '/etc/mysql/mysql.conf.d/mysqld.cnf'에서 각 변수에 대해 구성된 값은 MySQL에 의해 존중될 것입니다.

이 코드는 몇 년 된 것입니까?Django는 .96 이상부터 설정에 정의된 데이터베이스를 가지고 있습니다.제가 생각할 수 있는 다른 것은 multi-db 지원밖에 없는데, 이것은 상황을 조금 바꿨지만, 그마저도 1.1 또는 1.2였습니다.

특정 보기에 대한 특별한 DB가 필요한 경우에도 설정에서 정의하는 것이 좋을 것 같습니다.

SQLchemy는 이제 핑을 사용하여 연결의 새로움을 비관할 수 있는 방법에 대해 많은 정보를 제공합니다.

http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pessimistic

거기서부터.

from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool

@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
    cursor = dbapi_connection.cursor()
    try:
        cursor.execute("SELECT 1")
    except:
        # optional - dispose the whole pool
        # instead of invalidating one at a time
        # connection_proxy._pool.dispose()

        # raise DisconnectionError - pool will try
        # connecting again up to three times before raising.
        raise exc.DisconnectionError()
    cursor.close()

그리고 위의 내용이 제대로 작동하는지 확인하는 테스트:

from sqlalchemy import create_engine
e = create_engine("mysql://scott:tiger@localhost/test", echo_pool=True)
c1 = e.connect()
c2 = e.connect()
c3 = e.connect()
c1.close()
c2.close()
c3.close()

# pool size is now three.

print "Restart the server"
raw_input()

for i in xrange(10):
    c = e.connect()
    print c.execute("select 1").fetchall()
    c.close()

이 문제가 발생하여 구성을 변경할 수 있는 옵션이 없었습니다.문제가 50000 레코드 루프에서 49500개의 레코드가 발생하고 있다는 것을 알게 되었습니다. 왜냐하면 그 시점이 제가 (오래 전에 시도한 후) 두 번째 데이터베이스를 다시 시도하는 시점이었기 때문입니다.

그래서 저는 몇 천 개의 레코드마다 두 번째 데이터베이스를 다시 터치하도록 코드를 바꿨습니다(아주 작은 테이블의 카운트()로). 그리고 수정했습니다.의심할 여지 없이 "ping"이나 데이터베이스를 터치하는 다른 방법도 효과가 있을 것입니다.

session & environments , MySQL 과 을 해야 해야 합니다.wait_timeout그리고.interactive_timeout 는 해당 아래의 에 다시 해야 합니다.그리고 두 번째로 고객은 해당 환경 값 아래의 서버에 다시 연결해야 합니다.

언급URL : https://stackoverflow.com/questions/14163429/python-and-django-operationalerror-2006-mysql-server-has-gone-away

반응형