Riscrivi MySQL come mutex

0

La mia applicazione deve eseguire un'operazione ogni 10 minuti, ma quell'operazione viene attivata molte volte più frequentemente. Occasionalmente viene attivato tre o quattro volte al secondo in processi diversi, e questa è la cosa principale che voglio evitare.

È Django, e all'inizio ho usato la funzione django.core.cache , ma sono ancora ottenere più di un lavoratore eseguendo l'operazione contemporaneamente.

Anch'io ho Redis, e so che WATCH e MULTI possono essere usati per prevenire le condizioni di gara, ma i django-redis la libreria non li supporta.

Questa è la mia soluzione; si prega di commentare quanto bene (o non) impedisce a più lavoratori (processi) di eseguire l'operazione contemporaneamente:

  1. Avere una tabella MySQL con campi when e uuid e solo una riga singola che inizia con entrambi i valori NULL.
  2. Quando a un lavoratore viene detto di iniziare l'operazione, si chiude presto se when è inferiore a 10 minuti fa.
  3. Altrimenti, genera un UUID e lo memorizza nella tabella, aggiornando when in NOW() nella stessa query.
  4. Quindi, seleziona la riga e chiudi presto se uuid non corrisponde a quello appena generato.
  5. Altrimenti continua con l'operazione

Questo si basa su MySQL che impone l'ordine di letture e scritture e impone che solo una query acceda alla riga in una volta, il che potrebbe essere un assunzionamento non valido.

Qualsiasi altro modo per mantenere i processi di Celery dall'esecuzione simultanea di un'attività sarebbe altrettanto utile.

    
posta tar 29.08.2014 - 03:56
fonte

1 risposta

2

Quindi, la mia comprensione è

  • questa operazione è attivata dall'attività all'interno dell'applicazione
  • l'attività di attivazione può verificarsi fino a diverse volte al secondo
  • sebbene l'operazione sia attivata molte volte al secondo, dovrebbe eseguire una volta ogni dieci minuti.

Una tabella di una colonna sarebbe sufficiente:

create table Mutex (LastExecuted datetime NOT NULL);
insert Mutex(LastExecuted) values ('2010-01-01');

Inizializza la colonna con un valore arbitrario di almeno 10 minuti nel passato. L'inizializzazione su NULL introdurrà un caso speciale per la prima esecuzione che dovrà essere codificata.

Un lavoratore può prendere i diritti per eseguire il lavoro cercando di aggiornare questo valore

update Mutex
set LastExecuted = NOW()
where LastExecuted < DATE_SUB(NOW(), INTERVAL 10 MINUTE);

Cattura il numero di righe interessate da questa affermazione. Se l'istruzione riguarda zero righe, non sono passati 10 minuti. Se interessa 1 riga, il lavoratore corrente ha acquisito il mutex e dovrebbe eseguire l'operazione. Se interessa più di 1 riga, hai un problema con la tua applicazione!

Ciò fornirà anche protezione da un lavoratore che afferra il mutex e termina. Dopo 10 minuti un altro lavoratore sarà in grado di afferrare il diritto di lavorare.

    
risposta data 29.08.2014 - 06:01
fonte

Leggi altre domande sui tag