2016-03-17 29 views
7

Ciągle napotykam na dziwne problemy mysql, podczas gdy pracownicy wykonują zadania zaraz po utworzeniu.Tworzenie oddzielnego połączenia z bazą danych dla każdego pracownika selera

Używamy Django 1.3, seler 3.1.17, djorm-ext-pool 0,5

Rozpoczynamy proces selera z współbieżności 3. Moja obeservation tak daleko jest, gdy proces początek robotnicy, wszyscy dostają takie same mysql połączenie. Logujemy identyfikator połączenia db, jak poniżej.

from django.db import connection 
connection.cursor() 
logger.info("Task %s processing with db connection %s", str(task_id), str(connection.connection.thread_id())) 

Kiedy wszyscy pracownicy dostają zadania, pierwszy wykonuje z powodzeniem, ale pozostałe dwa daje dziwne błędy MySQL. To albo błędy z "odszedł serwer Mysql", albo z warunkiem, w którym Django zgłasza błąd "DoesNotExist". w oczywisty sposób istnieją obiekty, których zapytania Django istnieją.

Po tym błędzie każdy pracownik zaczyna uzyskiwać własne połączenie z bazą danych, po czym nie znajduje się żaden problem.

Jakie jest domyślne zachowanie selerów? Jest przeznaczony do udostępniania tego samego połączenia z bazą danych. Jeśli tak, to w jaki sposób odbywa się komunikacja między procesami? Idealnie wolałbym różne połączenia z bazą danych dla każdego pracownika.

Próbowałem kodu, o którym mowa poniżej, który nie działał. Celery Worker Database Connection Pooling

Poprawiliśmy także sugerowany poniżej kod selera. https://github.com/celery/celery/issues/2453

Dla tych, którzy zgodzili się na to pytanie, uprzejmie daj mi znać powód do spadku.

+0

Czy używasz oprogramowania pośredniego do łączenia puli Django? Jaka jest twoja konfiguracja CONN_MAX_AGE w konfiguracji django? Myślę, że to powoduje trwałe zachowanie połączenia w django. Może to być związane z zachowaniem, które widzisz, a nie z samym selerem. –

+0

Czy możesz po prostu uruchomić współbieżność = 1 i uruchomić wielu pracowników? –

+0

@AlexLuisArias Który uruchamiałby tylko jeden proces roboczy i nie dotyczy tego problemu. –

Odpowiedz

2

Seler jest uruchamiany z poniższej komendy

celery -A myproject worker --loglevel=debug --concurrency=3 -Q testqueue 

myproject.py jako część procesu nadrzędnego robił kilka zapytań do bazy danych MySQL przed rozwidlone procesy robocze.

W ramach przepływu zapytań w procesie głównym django ORM tworzy pulę połączeń sqlalchemy, jeśli jeszcze nie istnieje. Następnie tworzone są procesy robocze.

Seler jako część pakietu django zamyka istniejące połączenia.

def close_database(self, **kwargs): 
    if self._close_old_connections: 
     return self._close_old_connections() # Django 1.6 
    if not self.db_reuse_max: 
     return self._close_database() 
    if self._db_recycles >= self.db_reuse_max * 2: 
     self._db_recycles = 0 
     self._close_database() 
    self._db_recycles += 1 

W efekcie, co może być dzieje jest to, że obiekt basen sqlalchemy z jednej niewykorzystanej połączenia db zostanie skopiowany do procesu 3 pracowników kiedy rozwidlone. Tak więc 3 różne pule mają 3 obiekty połączenia wskazujące ten sam deskryptor pliku połączenia.

Pracownicy wykonujący zadania na żądanie połączenia db, wszyscy pracownicy otrzymują to samo nieużywane połączenie z puli sqlalchemy, ponieważ jest ono obecnie nieużywane. Fakt, że wszystkie połączenia wskazują na ten sam deskryptor pliku, spowodował błędy w połączeniu MySQL.

Utworzone tam nowe połączenia są nowe i nie wskazują tego samego deskryptora pliku gniazda.

Rozwiązanie:

W głównym procesie dodać

from django.db import connection 
connection.cursor() 

zanim jakikolwiek import jest zrobione. tj. przed dodaniem modułu djorm-ext-pool.

W ten sposób wszystkie zapytania db będą korzystać z połączeń utworzonych przez django poza pulą. Kiedy seniorzy django fixup zamykają połączenie, połączenie faktycznie zostaje zamknięte, a nie wraca do puli alchemików, pozostawiając pulę alchemiczną bez żadnych połączeń w momencie, gdy w momencie poradzenia sobie z nią poradzimy sobie z wszystkimi pracownikami. Tam, gdy pracownicy prosi o połączenie db, sqlalchemy zwraca jeden z nowo utworzonych połączeń.