10

Ehi. Io uso delayed_job per l'elaborazione in background. Ho 8 CPU del server, MySQL e inizio 7 delayed_job elaboraRails che eseguono più delayed_job - lock tables

RAILS_ENV=production script/delayed_job -n 7 start 

Q1: sto chiedendo è possibile che 2 o più processi delayed_job avviare l'elaborazione dello stesso processo (lo stesso record fila in il database delayed_jobs). Ho controllato il codice del plugin delayed_job ma non riesco a trovare la direttiva lock in un modo che dovrebbe essere (nessuna tabella lock o SELECT ... FOR UPDATE).

Penso che ogni processo dovrebbe bloccare la tabella del database prima di eseguire un UPDATE sulla colonna lock_by. Bloccano il record semplicemente aggiornando il campo locked_by (UPDATE delayed_jobs SET locked_by ...). È abbastanza? Non è necessario il blocco? Perché? So che UPDATE ha una priorità più alta di SELECT ma penso che questo non abbia l'effetto in questo caso.

La mia comprensione della situazione multy-threaded è:

Process1: Get waiting job X. [OK] 
Process2: Get waiting jobs X. [OK] 
Process1: Update locked_by field. [OK] 
Process2: Update locked_by field. [OK] 
Process1: Get waiting job X. [Already processed] 
Process2: Get waiting jobs X. [Already processed] 

Penso che in alcuni casi, più posti di lavoro possono ottenere le stesse informazioni e possono avviare l'elaborazione lo stesso processo.

Q2: 7 il ritardo è un buon numero per il server 8CPU? Perché sì/no.

Thx 10x!

risposta

11

Penso che la risposta alla tua domanda è in linea 168 di 'lib/delayed_job/job.rb':

self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?)", id, (now - max_run_time.to_i)]) 

Ecco l'aggiornamento della riga viene eseguita solo se nessun altro lavoratore ha già bloccato il lavoro e questo viene verificato se la tabella viene aggiornata. Un lock da tavolo o simile (che tra l'altro ridurrebbe enormemente le prestazioni della tua app) non è necessario, dal momento che il tuo DBMS assicura che l'esecuzione di una singola query sia isolata dagli effetti di altre query. Nel tuo esempio Process2 non può ottenere il blocco per il lavoro X, poiché aggiorna la tabella dei lavori se e solo se prima non era bloccato.

Alla tua seconda domanda: dipende. Su un server con 8 CPU. che è dedicato a questo lavoro, 8 lavoratori sono un buon punto di partenza, dato che i lavoratori sono a thread singolo, dovresti eseguirne uno per ogni core. A seconda della configurazione, più o meno lavoratori sono migliori. Dipende pesantemente dal tuo lavoro. Prendi il tuo lavoro vantaggioso dei nuclei mutiple? Oppure il tuo lavoro aspetta la maggior parte del tempo per risorse esterne? Hai sperimentato diverse impostazioni e hai dato un'occhiata a tutte le risorse coinvolte.

+0

Quindi stai dicendo che ogni processo è atom-style ed è sicuro? – xpepermint

+0

Quello che penso manchi qui è SELECT ... FOR UPDATE. ? – xpepermint

+0

La query è atomica. Quindi se si esegue la query 'UPDATE jobs SET locked_at = '..', locked_by = 1 WHERE id = 12 e (locked_at è null o locked_at <'..')', quindi locked_at e locked_by vengono aggiornati solo se non c'è altro blocco valido. Il DBMS prima controlla la condizione where e quindi esegue l'aggiornamento e assicura che la riga non venga modificata in mezzo. Quindi non è possibile sovrascrivere un blocco esistente. – gregor