2014-11-16 8 views
8

ho recentemente aggiornato da Django 1.4 a Django 1.7 e dal momento che continuo a ricevere il seguente messaggio di errore per alcuni script, a volte:Django, dopo l'aggiornamento: server MySQL è andato via

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

Gli script sono molto attività lunghe o in esecuzione continua che potrebbero comportare fasi di non comunicazione con il db per diversi minuti, quindi la connessione scade. Tuttavia, prima di essere aggiornato, non c'era alcun problema, dato che Django sembrava ristabilire automaticamente una connessione. Ora non significa che le attività spesso si fermano e falliscono nel mezzo.

Qualcuno sa cosa è cambiato e come posso risolvere il problema?

è forse legata a quella biglietto/fix: https://code.djangoproject.com/ticket/21463

Grazie mille!

+0

Controllare [questo] (https://code.djangoproject.com/ticket/21597 # commento: 29) e [questo] (http://piwik.org/faq/troubleshooting/faq_183/). –

risposta

16

Il motivo di tale comportamento è la connessione permanente al database, introdotta in Django 1.6.

Per evitare l'errore di timeout di connessione è necessario impostare CONN_MAX_AGE in settings.py al valore che è meno di wait_timeout in MySQL config (my.cnf). In quel caso Django rileva che la connessione deve essere riaperta prima che MySQL la lanci. Il valore predefinito per MySQL 5.7 è 28800 secondi.

settings.py:

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

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

my.cnf:

wait_timeout = 28800 

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

3

In django 1.6, quando è passato il wait_timeout (di mysql), l'accesso al database causa l'errore (2006, 'MySQL server è andato via'). Questo non era il caso in django 1.5.1

Ho notato questo errore quando uso lavoratori che eseguono il codice django (usando gearman).

di riprodursi:

impostare il timeout a basso valore modificando /etc/mysql/my.cnf aggiungere il seguente sotto [mysqld]

wait_timeout = 10 
interactive_timeout = 10 

Poi

% pitone manage.py shell

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

Ora si ottiene l'errore.

soluzione semplice che ho trovato sul web è quello di chiamare django.db.close_connection() prima che l'accesso

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

funziona bene.

7

Ho un processo in background in esecuzione rqworker wh Esegue lavori separati per aggiornare alcuni dati dopo alcune azioni dell'utente.

Io ottengo sempre OperationalError: (2006, 'MySQL server has gone away') se non ci sono stati azioni dell'utente durante più di wait_timeout secondi. Anche se ho impostato CONN_MAX_AGE inferiore a MySQL wait_timeout.

Come ho capito, il cambio di CONN_MAX_AGE potrebbe aiutare se Django ha verificato e chiuso le sue connessioni automaticamente da questo timeout. Ma Django 1.7.x lo controlla solo prima e dopo ogni richiesta (vedi django/db/init.py#L101-L112).

Come descritto in Django ticket 15119, possiamo vedere che Django stava eseguendo un ping per convalidare se la connessione era attiva prima di eseguire ogni query. Questo comportamento è stato risolto in commit 282b2f4.

sviluppatori Django ha dato una risposta breve per tutte le domande di questo tipo in https://code.djangoproject.com/ticket/21597#comment:29

Pertanto il mio processo rqworker deve validare stessa connessione per ogni nuovo posto di lavoro. (Nota: se chiudiamo una connessione, Django ne creerà una nuova).

Ho intenzione di utilizzare l'approccio Django per richiesta per i lavori e di chiamare django.db.close_old_connections() prima e dopo ogni lavoro. E sì, CONN_MAX_AGE dovrebbe essere inferiore a MySQL wait_timeout, perché Django non controlla se MySQL server has gone away nel metodo django.db.close_old_connections().

1

Forse il timeout è un problema per alcuni, ma mi sono imbattuto in questo problema quando provavo a scrivere un campo BLOB molto grande. Decisi che, aumentando al massimo consentito per le dimensioni dei pacchetti nel file di configurazione di MySQL ...

max_allowed_packet = 4M

Non dimenticate di riavviare mysql dopo la modifica al /etc/my.cnf. Questa pagina ha aiutato ...

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

0

abbiamo notato anche questo. La risposta sopra riportata per impostare CONN_MAX_AGE su qualcosa di meno di Wait_timeout di MySQL/MariaDB funziona - per il web.

Per le attività di lunga durata, tuttavia, questo non sembra funzionare. Invece lo avviluppiamo e chiudiamo la connessione ogni volta che viene eseguita una delle nostre attività di lunga durata.

Combiniamo questo con il nostro pool personalizzato. Prendilo o lascialo: il Django predefinito ha zero control, non qualcosa che ci è piaciuto in produzione. Impostiamo un pool massimo per uccidere il server prima che uccida il DB con troppe connessioni.Usalo come decoratore per le attività:

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

''' 
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