tutorial digitalocean deploy python mysql django nginx django-middleware

digitalocean - Python y Django OperationalError(2006, ''servidor MySQL se ha ido'')



python django hosting free (10)

¿Qué edad tiene este código? Django tiene bases de datos definidas en la configuración desde al menos .96. Solo otra cosa que puedo pensar es soporte multi-db, que cambió un poco las cosas, pero incluso eso fue 1.1 o 1.2.

Incluso si necesita una base de datos especial para ciertas vistas, creo que es mejor que la defina en la configuración.

Original: Recientemente comencé a obtener MySQL OperationalErrors de parte de mi código anterior y parece que no puedo rastrear el problema. Como estaba funcionando antes, pensé que podría haber sido una actualización de software que rompió algo. Estoy usando python 2.7 con django runfcgi con nginx. Aquí está mi código original:

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()

He intentado lo siguiente, pero todavía no funciona:

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()

Actualmente, mi única solución es hacer MySQLdb.connect() en cada función que usa mysql. También noté que al usar el manage.py runserver , no tendría este problema mientras que nginx lanzaría estos errores. Dudo que esté agotando el tiempo de conexión porque se está llamando a list() pocos segundos después de iniciar el servidor. ¿Hubo alguna actualización del software que estoy utilizando que podría hacer que esto se rompa / hay alguna solución para esto?

Editar: Me di cuenta de que recientemente escribí una pieza de middleware para demonizar una función y esta fue la causa del problema. Sin embargo, no puedo entender por qué. Aquí está el código para el middle ware

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)


A veces, si ve "OperationalError: (2006, ''servidor MySQL se ha ido'')", es porque está emitiendo una consulta que es demasiado grande. Esto puede suceder, por ejemplo, si está almacenando sus sesiones en MySQL, y está tratando de poner algo realmente grande en la sesión. Para solucionar el problema, debe aumentar el valor de la configuración max_allowed_packet en MySQL.

El valor predeterminado es 1048576.

Entonces, vea el valor actual para el valor predeterminado, ejecute el siguiente SQL:

select @@max_allowed_packet;

Para establecer temporalmente un nuevo valor, ejecute el siguiente SQL:

set global max_allowed_packet=10485760;

Para solucionar el problema de forma más permanente, cree un archivo /etc/my.cnf con al menos lo siguiente:

[mysqld] max_allowed_packet = 16M

Después de editar /etc/my.cnf, necesitará reiniciar MySQL o reiniciar su máquina si no sabe cómo hacerlo.


Compruebe si puede crear un objeto de conexión mysql en un hilo y luego usarlo en otro.

Si está prohibido, use threading.Local para conexiones por subproceso:

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(...)


En mi opinión, el problema común de esta advertencia es el hecho de que su aplicación ha alcanzado el valor wait_timeout de MySQL.

Tuve el mismo problema con una aplicación PythonFLASK que desarrollé y resolví muy fácil.

PD: estaba usando MySQL 5.7.14

$ 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

Una observación importante: si busca las variables a través del modo por lotes MySQL, los valores aparecerán tal como están. Pero si realiza "SHOW VARIABLES LIKE ''wait%'';" o "SHOW VARIABLES LIKE ''interactive%'';", el valor configurado para ''interactive_timeout'' aparecerá en ambas variables, y no sé por qué, pero el hecho es que los valores configurados para cada variable en ''/ etc /mysql/mysql.conf.d/mysqld.cnf '', será respetado por el proceso de MySQL.

¡Saludos!


En primer lugar, debe asegurarse de que la sesión de MySQL y los wait_timeout globales wait_timeout interactive_timeout valores wait_timeout y interactive_timeout . Y en segundo lugar, su cliente debe intentar reconectarse con el servidor por debajo de esos valores de entorno.


Este error es misterioso porque MySQL no informa por qué se desconecta, simplemente desaparece.

Parece que hay muchas causas de este tipo de desconexión. Una que acabo de encontrar es que, si la cadena de consulta es demasiado grande, el servidor se desconectará. Esto probablemente se relaciona con la configuración max_allowed_packets .


He estado luchando con este problema también. No me gusta la idea de aumentar el tiempo de espera en mysqlserver. Autoreconnect con CONNECTION_MAX_AGE tampoco funciona como se mencionó. Lamentablemente, terminé envolviendo cada método que consulta la base de datos como este

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)

Como puede ver, prefiero capturar la excepción que hacer ping a la base de datos cada vez antes de consultarlo. Porque capturar una excepción es un caso raro. Esperaría que django se reconectara automáticamente pero parecían refused ese problema.


SQLAlchemy ahora tiene un excelente artículo sobre cómo puedes usar el ping para ser pesimista sobre la frescura de tu conexión:

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

Desde allí,

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()

Y una prueba para asegurarse de que lo anterior funcione:

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()


Según la documentación de MySQL , su mensaje de error aparece cuando el cliente no puede enviar una pregunta al servidor, muy probablemente porque el servidor ha cerrado la conexión. En el caso más común, el servidor cerrará una conexión inactiva después de un (predeterminado) de 8 horas. Esto es configurable en el lado del servidor.

La documentación de MySQL ofrece una serie de otras posibles causas que podrían valer la pena examinar para ver si se ajustan a su situación.

Una alternativa a llamar a connect() en cada función (que podría terminar creando innecesariamente conexiones nuevas) sería investigar usando el método ping() en el objeto de conexión; esto prueba la conexión con la opción de intentar una reconexión automática. Luché para encontrar en línea una documentación decente para el método ping() , pero la respuesta a esta pregunta podría ayudar.

Tenga en cuenta que la reconexión automática puede ser peligrosa al manejar transacciones, ya que parece que la reconexión ocasiona una reversión implícita (y parece ser la razón principal por la que la reconexión automática no es una característica de la implementación de MySQLdb).


Tuve este problema y no tuve la opción de cambiar mi configuración. Finalmente descubrí que el problema estaba ocurriendo 49500 registros en mi bucle de 50000 registros, porque esa era la misma vez que lo intentaba de nuevo (después de haberlo intentado hace mucho tiempo) para acceder a mi segunda base de datos.

Así que cambié mi código para que cada pocos miles de registros tocara la segunda base de datos otra vez (con un recuento () de una tabla muy pequeña), y eso lo solucionó. Sin duda, "ping" u otros medios para tocar la base de datos también funcionarían.