2012-10-31 8 views
6

Sto rivedendo un sistema che invierà messaggi via http a uno dei numerosi fornitori. L'originale è script perl ed è probabile che anche il re-sviluppo utilizzi perl.Per forchetta o non forchetta?

Nel vecchio sistema, c'erano un numero di script perl tutti in esecuzione contemporaneamente, cinque per ogni fornitore. Quando un messaggio è stato inserito nel database, è stato scelto un numero di thread casuale (1-5) e il fornitore è stato scelto per garantire che nessun messaggio è stato elaborato due volte evitando di dover bloccare la tabella/riga. Inoltre, nel database era presente un campo "Fair Queue Position" per garantire che un invio di messaggi di grandi dimensioni non ritardasse le piccole mandate avvenute mentre veniva inviato il messaggio più grande.

In alcuni momenti ci sarebbero solo un paio di messaggi al minuto, ma in altri momenti ci sarebbe una discarica di potenzialmente centinaia di migliaia di messaggi. Mi sembra uno spreco di risorse avere tutti gli script in esecuzione e controllare i messaggi tutto il tempo, quindi sto cercando di capire se c'è un modo migliore per farlo, o se la vecchia maniera è accettabile.

Il mio pensiero in questo momento si trovano con l'idea di avere uno script che viene eseguito e forchette come molti processi figli quanti sono necessari (fino ad un limite) a seconda di quanto traffico c'è, ma non sono sicuro modo migliore per attuare è tale che ogni messaggio viene elaborato solo una volta, mentre viene mantenuta la giusta coda.

La mia ipotesi migliore ora è che lo script padre aggiorna il DB per indicare quale processo figlio dovrebbe gestirlo, tuttavia sono preoccupato che questo finirà per essere meno efficiente rispetto al metodo originale. Ho poca esperienza nella scrittura del codice di forking (l'ultima volta che l'ho fatto era circa 15 anni fa).

Qualsiasi idea o collegamento alle guide sul modo migliore per elaborare le code di messaggi apprezzate!

+0

Hai guardato Gearman o uno degli altri server di lavoro là fuori? – jshy

risposta

8

È possibile utilizzare Thread :: Queue o qualsiasi altro da questo: Is there a multiprocessing module for Perl?

Se il vecchio sistema è stato scritto in Perl in questo modo è possibile riutilizzarne la maggior parte.

non esempio di lavoro:

use strict; 
use warnings; 

use threads; 
use Thread::Queue; 

my $q = Thread::Queue->new(); # A new empty queue 

# Worker thread 
my @thrs = threads->create(sub { 
          while (my $item = $q->dequeue()) { 
           # Do work on $item 
          } 
         })->detach() for 1..10;#for 10 threads 
my $dbh = ... 
while (1){ 
    #get items from db 
    my @items = get_items_from_db($dbh); 
    # Send work to the thread 
    $q->enqueue(@items); 
    print "Pending items: "$q->pending()."\n"; 
    sleep 15;#check DB in every 15 secs 
} 
6

Suggerirei di utilizzare un server di messaggi come RabbitMQ.

Un feed di processo funziona nella coda e è possibile che più processi di lavoro utilizzino la coda.

I vantaggi di questo approccio:

  • lavoratori bloccano quando in attesa di lavoro (senza tempi di attesa occupato)
  • più processi di lavoro possono essere avviati manualmente se necessario
  • processi di lavoro non devono essere un figlio di un processo genitore speciale
  • RabbitMQ distribuirà il lavoro tra tutti i lavoratori che sono pronti ad accettare i lavori
  • RabbitMQ riporterà il lavoro in coda se il lavoratore fa non restituire un ACK
  • non è necessario assegnare lavoro nel database
  • ogni "agente" (lavoratore, produttore, ecc.) È un processo indipendente che significa che si può uccidere o riavviarlo senza influenzare altri processi

di scale-up o verso il basso gli operai numero in modo dinamico, è possibile implementare qualcosa di simile:

  1. hanno automaticamente lavoratori morire se non ottengono il lavoro per un determinato periodo di tempo
  2. hanno un altro processo monitorare la lunghezza della coda e deporre le uova più lavoratori se la coda sta diventando troppo grande
+0

Per quanto posso dire, questo è fondamentalmente ciò che è stato implementato in origine. I produttori sono le pagine Web che inseriscono i messaggi nel database, le code sono equivalenti alla combinazione di fornitore e thread nel DB e i processi di lavoro (consumatori) sono equivalenti a ciascuno degli script perl che sono in esecuzione tutto il tempo. Tuttavia la seconda parte del tuo post su ridimensionamento dinamico mi dà spunti di riflessione. Grazie! –

+1

Se si utilizza un database per la coda, i lavoratori dovranno attendere (cioè eseguire periodicamente il polling del database). Un server di code messaggi gestirà la distribuzione del lavoro e consentirà ai lavoratori di bloccare (cioè non consumare tempo CPU) finché c'è del lavoro da fare. – ErikR

1

mi consiglia di utilizzare beanstalkd per un server di lavoro dedicato, e Beanstalk::Client nei vostri script perl per l'aggiunta di posti di lavoro alla coda e rimuoverli.

Si dovrebbe trovare beanstalkd più facile da installare e configurare rispetto a RabbitMQ. Si occuperà inoltre di distribuire i posti di lavoro tra i lavoratori disponibili, seppellendo eventuali lavori falliti, in modo che possano essere riprovati in seguito, pianificando i lavori da svolgere in un secondo momento e molte altre funzionalità di base. Per il tuo lavoratore, non devi preoccuparti di biforcarsi o infilare fili; avvia appena tutti i lavoratori di cui hai bisogno, su tutti i server che hai a disposizione.

O RabbitMQ o Beanstalk sarebbe meglio che ruotare la propria soluzione db-backed. Questi progetti hanno già elaborato molti dei dettagli necessari per l'accodamento e implementato funzionalità che potresti non realizzare ancora che desideri. Dovrebbero anche gestire i sondaggi per nuovi posti di lavoro in modo più efficiente, rispetto a dormire e selezionare dal database per vedere se c'è altro lavoro da fare.

Problemi correlati