2010-11-21 11 views
11

Dopo aver parlato con un mio amico di Google, vorrei implementare una sorta di modello Lavoro/Lavoratore per aggiornare il mio set di dati.Devo imparare/utilizzare MapReduce o qualche altro tipo di parallelizzazione per questa attività?

Questo set di dati rispecchia i dati di un servizio di terze parti, pertanto, per eseguire l'aggiornamento, è necessario effettuare diverse chiamate remote alle proprie API. Penso che passeremo molto tempo in attesa di risposte da questo servizio di terze parti. Mi piacerebbe accelerare le cose e utilizzare meglio le ore di calcolo, parallelizzando queste richieste e mantenendo aperte molte di esse contemporaneamente, in attesa delle loro risposte individuali.

Prima di spiegare il mio gruppo di dati specifici e ottenere nel problema, vorrei chiarire che cosa le risposte che sto cercando:

  1. Si tratta di un flusso che sarebbe adatto a parallelizzazione con MapReduce?
  2. Se , sarebbe economicamente vantaggioso eseguirlo sul modulo mapreduce di Amazon, che fattura all'ora e alle ore di arrotondamento quando il lavoro è completo? (Non sono sicuro di quello che conta come "lavoro", quindi non so esattamente come mi verrà addebitato)
  3. Se no, Esiste un altro sistema/schema che dovrei usare? e C'è una libreria che mi aiuterà a farlo in python (su AWS, usign EC2 + EBS)?
  4. Ci sono dei problemi che vedi nel modo in cui ho progettato questo flusso di lavoro?

Ok, ora sui dettagli:

Il set di dati è costituito da utenti che dispongono di elementi preferiti e che seguono altri utenti. L'obiettivo è essere in grado di aggiornare la coda di ogni utente: l'elenco di elementi che l'utente vedrà quando caricherà la pagina, in base agli elementi preferiti degli utenti che segue. Ma, prima di poter elaborare i dati e aggiornare la coda di un utente, devo assicurarmi di avere i dati più aggiornati, ovvero da dove arrivano le chiamate API.

Ci sono due chiamate che posso fare :

  • convincere gli utenti seguito - che restituisce tutti gli utenti seguiti dall'utente richiesto, e
  • ottenere oggetti preferiti - che restituisce tutti gli elementi preferiti dell'utente richiesto.

Dopo che io chiamo get utenti seguiti per l'utente in fase di aggiornamento, ho bisogno di aggiornare gli elementi preferiti per ogni utente di essere seguito. Solo quando tutti i preferiti vengono restituiti per tutti gli utenti che vengono seguiti, posso iniziare a elaborare la coda per quell'utente originale. Questo flusso si presenta come:

Updating UserX's Queue

Lavoro in questo flusso sono:

  • avviare l'aggiornamento coda per l'utente - prende il via il processo mediante il recupero degli utenti seguiti dall'utente in fase di aggiornamento, memorizzandoli e creando quindi Ottieni i lavori preferiti per ciascun utente.
  • Ottieni preferiti per l'utente - Richiede e memorizza, un elenco di preferiti per l'utente specificato, dal servizio di terze parti.
  • Calcola nuova coda per l'utente: elabora una nuova coda, ora che tutti i dati sono stati recuperati e quindi memorizza i risultati in una cache utilizzata dal livello applicazione.

Così, ancora una volta, le mie domande sono:

  1. Si tratta di un flusso che sarebbe adatto a parallelizzazione con MapReduce? Non so se mi permetterebbe di avviare il processo per UserX, recuperare tutti i dati relativi, e tornare a elaborare la coda di UserX solo dopo aver fatto tutto.
  2. Se , sarebbe economicamente vantaggioso eseguirlo sul modulo mapreduce di Amazon, che fattura all'ora e alle ore di arrotondamento quando il lavoro è completo? C'è un limite al numero di "thread" che posso aspettare sulle richieste API aperte se utilizzo il loro modulo?
  3. Se no, C'è un altro sistema/schema che dovrei usare? e C'è una libreria che mi aiuterà a farlo in python (su AWS, usign EC2 + EBS?)?
  4. Ci sono dei problemi che vedi nel modo in cui ho progettato questo flusso di lavoro?

Grazie per la lettura, non vedo l'ora di discutere con tutti voi.

Modifica, in risposta a JimR:

Grazie per una risposta solida. Nella mia lettura da quando ho scritto la domanda originale, mi sono distolto dall'uso di MapReduce. Non ho ancora deciso per certo come voglio costruire questo, ma sto iniziando a sentire che MapReduce è migliore per distribuire/parallelizzare il carico di calcolo quando sto solo cercando di parallelizzare le richieste HTTP.

Quale sarebbe stato il mio compito di "ridurre", la parte che prende tutti i dati recuperati e la scricchiola in risultati, non è molto intensa dal punto di vista computazionale. Sono abbastanza sicuro che finirà per essere una grande query SQL che viene eseguita per un secondo o due per utente.

Quindi, quello che sto appoggiato verso è:

  • A/modello non MapReduce lavoro operaio, scritto in Python . Un mio amico google mi ha dato l'opportunità di imparare Python per questo, dato che è un overhead basso e si adatta bene.
  • Utilizzo di Amazon EC2 come livello di calcolo. Penso che questo significhi anche bisogno di una fetta EBS per archiviare il mio database.
  • Possibilmente utilizzando la coda dei messaggi semplici di Amazon thingy. Sembra che questo terzo widget di Amazon sia progettato per tenere traccia delle code di lavoro, spostare i risultati da una attività agli input di un'altra e gestire con grazia le attività non riuscite. È molto economico Può valere la pena implementare invece di un sistema di coda dei lavori personalizzato.
+0

Ho utilizzato il motore di app di google per richieste altamente parallele e la gestione quasi in tempo reale di questo tipo di problema. MapReduce ha avuto un sovraccarico molto più alto di avvio e di lavoro rispetto a quello che stavo cercando. – kevpie

+0

Interessante. So che il motore delle app può usare python, che è quello su cui ho iniziato a scrivere questi lavori, ma non so in quale altro modo utilizzerei GAE per questo. Non ho familiarità con il funzionamento di GAE, né con il modo di esprimere questo problema, quindi non riesco a trovare le mie risposte. Avete altre risorse che dovrei guardare qui? Grazie per il consiglio! –

+0

In realtà ho scritto un processo Python che utilizzava thread e accodamento per eseguire richieste web parallele e l'elaborazione dei dati. Ha funzionato bene, ma non ero "completamente esperto" nella programmazione Python, o nei thread, per renderlo veramente affidabile, o per funzionare bene. Dopo molte ricerche su google e alcune frustrazioni e altri compiti che richiedono priorità, ho abbandonato di lavorarci su. Potrei riprenderlo. Sono arrivato a conclusioni simili riguardo al lavoro con MapReduce, dal momento che non avrei mai sfruttato nulla se non il parallelismo costruito in hadoop. Ad ogni modo, se vuoi chattare di più sugli approcci e le soluzioni, lmk! –

risposta

1

Sembra che stiamo andando con Node.js e la libreria di controllo del flusso Seq. È stato molto facile passare dalla mia mappa/diagramma di flusso del processo a uno stubb del codice, e ora è solo questione di compilare il codice per collegarlo alle giuste API.

Grazie per le risposte, sono state di grande aiuto nel trovare la soluzione che stavo cercando.

0

Sto lavorando con un problema simile che ho bisogno di risolvere. Stavo anche guardando MapReduce e usando il servizio Elastic MapReduce di Amazon.

Sono abbastanza convinto che MapReduce funzionerà per questo problema. L'implementazione è dove mi sto bloccando, perché non sono sicuro che il mio riduttore debba fare qualcosa.

Risponderò alle tue domande nel momento in cui comprenderò il tuo (e il mio) problema, e spero che sia d'aiuto.

  1. Sì, penso che andrà bene. Potresti considerare l'utilizzo dell'opzione per più passaggi del servizio Elastic MapReduce. Potresti usare 1 Step per recuperare le persone che un utente sta seguendo, e un altro passo per compilare un elenco di tracce per ciascuno di quei follower, e il riduttore per quel 2 ° passo sarebbe probabilmente quello per costruire la cache.

  2. dipende da quanto è grande il vostro set di dati è e quanto spesso ti verrà eseguirlo. È difficile dire senza sapere quanto grande sia il set di dati (o che otterrà) se sarà conveniente o meno. Inizialmente, probabilmente sarà abbastanza economico, in quanto non dovrai gestire il tuo cluster di hadoop, né dover pagare per le istanze EC2 (supponendo che sia quello che usi) di essere attivo tutto il tempo. Una volta raggiunto il punto in cui stai effettivamente elaborando questi dati per un lungo periodo di tempo, probabilmente avrà sempre meno senso usare il servizio MapReduce di Amazon, perché avrai sempre nodi online sempre.

Un lavoro è fondamentalmente l'attività MapReduce. Può consistere in più passaggi (ogni attività MapReduce è un passaggio). Una volta che i tuoi dati sono stati elaborati e tutti i passaggi sono stati completati, il tuo lavoro è finito. Quindi stai effettivamente pagando il tempo di CPU per ogni nodo nel cluster Hadoop. quindi, T * n dove T è il Tempo (in ore) necessario per elaborare i tuoi dati, e n è il numero di nodi che dici a Amazon di far girare.

Spero che questo aiuti, buona fortuna. Mi piacerebbe sapere come finisci per implementare i tuoi Mappers and Reducers, poiché sto risolvendo un problema molto simile e non sono sicuro che il mio approccio sia davvero il migliore.

+0

Buona risposta. Ho postato una risposta nell'articolo principale che spiega a cosa mi sto orientando e perché. Spero che ciò ti aiuti e buona fortuna! –

5

Il lavoro che descrivi è probabilmente adatto per una coda o una combinazione di coda e job server. Certamente potrebbe funzionare anche come una serie di passi di MapReduce.

Per un server di lavoro, consiglio di guardare Gearman. La documentazione non è eccezionale, ma le presentazioni fanno un ottimo lavoro per documentarlo, e anche il modulo Python è abbastanza auto-esplicativo.

In sostanza, si creano le funzioni nel server di lavoro, e queste funzioni vengono chiamati dai clienti tramite un API. Le funzioni possono essere chiamate sia in modo sincrono che asincrono. Nel tuo esempio, probabilmente vuoi aggiungere in modo asincrono il lavoro "Avvia aggiornamento". Ciò svolgerà qualsiasi compito preparatorio e quindi chiamerà in modo asincrono il lavoro "Segui gli utenti". Quel lavoro preleverà gli utenti, quindi chiamerà il lavoro "Aggiorna utenti seguiti". Questo invierà tutti i "Ottieni preferiti per l'utente" e i lavori degli amici insieme in una volta sola, e attenderà in sincrono il risultato di tutti loro. Quando saranno tutti ritornati, chiamerà il lavoro "Calcola nuova coda".

Questo approccio job-server solo sarà inizialmente un po 'meno robusto, dal momento in modo che a gestire gli errori e server qualsiasi verso il basso e la persistenza correttamente sta per essere divertente.

Per una coda, SQS è una scelta ovvia. È solido come una roccia e molto veloce da accedere da EC2 ed economico. E molto più semplice da configurare e gestire rispetto alle altre code quando sei appena iniziato.

In sostanza, si vuole mettere un messaggio nella coda, proprio come si potrebbe inviare un lavoro al server di lavoro di cui sopra, ad eccezione probabilmente non fare nulla in modo sincrono.Invece di creare "Ottieni i preferiti per l'utente" e così via, le chiamate in modo sincrono, le renderai in modo asincrono, e poi avrai un messaggio che dice di controllare se tutte sono finite. Avrai bisogno di una sorta di persistenza (un database SQL con cui hai familiarità, o SimpleDB di Amazon se vuoi andare completamente AWS) per controllare se il lavoro è stato eseguito - non puoi controllare lo stato di avanzamento di un lavoro in SQS (anche se è possibile in altre code). Il messaggio che controlla se sono tutti completati farà il controllo - se non sono tutti finiti, non fare nulla, e quindi il messaggio verrà ritentato in pochi minuti (basato su visibility_timeout). Altrimenti, puoi mettere il prossimo messaggio in coda.

Questo approccio solo code dovrebbe essere robusto, presupponendo che non si consumino messaggi in coda per errore senza eseguire il lavoro. Fare un errore del genere è difficile da fare con SQS - devi davvero provarci. Non utilizzare code o protocolli che consumano automaticamente. In caso di errore, potresti non essere in grado di assicurarti di reinserire un messaggio sostitutivo sulla coda.

In questo caso può essere utile una combinazione di coda e job server. È possibile evitare di non disporre di un archivio di persistenza per verificare l'avanzamento del lavoro: il Job Server ti consentirà di tenere traccia dell'avanzamento del lavoro. Il tuo messaggio "ottieni favoriti per gli utenti" potrebbe collocare tutti i lavori "Ottieni preferiti per UtenteA/B/C" nel Job Server. Quindi, metti un messaggio di "controllo di tutti i favoriti di prelievo" sulla coda con un elenco di attività che devono essere completate (e sufficienti informazioni per riavviare tutti i lavori che misteriosamente scompaiono).

per i punti bonus:

Facendo questo come un MapReduce dovrebbe essere abbastanza facile.

Il primo input del tuo lavoro sarà un elenco di tutti i tuoi utenti. La mappa avrà ogni utente, ottenere gli utenti seguiti, e linee di uscita per ogni utente e il loro utente seguito:

"UserX" "UserA" 
"UserX" "UserB" 
"UserX" "UserC" 

Un'identità ridurre passo lascerà questo invariata. Questo formerà l'input del secondo lavoro. La mappa per il secondo lavoro otterrà i favoriti per ciascuna linea (si consiglia di utilizzare memcached per impedire il recupero preferiti per UserX/combo UtenteA e Usery/UtenteA tramite l'API), e l'uscita di una riga per ogni preferito:

"UserX" "UserA" "Favourite1" 
"UserX" "UserA" "Favourite2" 
"UserX" "UserA" "Favourite3" 
"UserX" "UserB" "Favourite4" 

L'ridurre passo per questo lavoro permette di convertire questo:

"UserX" [("UserA", "Favourite1"), ("UserA", "Favourite2"), ("UserA", "Favourite3"), ("UserB", "Favourite4")] 

a questo punto, si potrebbe avere un altro lavoro MapReduce per aggiornare il database per ogni utente con questi valori, o si potrebbe essere in grado di utilizzare alcuni degli strumenti relativi a Hadoop come Pig, Hive e HBase per gestire il tuo database per te.

Io consiglio di utilizzare Cloudera's Distribution per i comandi di gestione di ec2 di Hadoop per creare e distruggere il cluster Hadoop su EC2 (le loro AMI hanno Python impostato su di essi) e utilizzare qualcosa come Dumbo (su PyPI) per creare il tuo MapReduce lavori, poiché consente di testare i lavori MapReduce sulla macchina locale/dev senza accedere a Hadoop.

Buona fortuna!

+1

Grazie per una risposta molto approfondita. Andare a sedersi e passare attraverso questo correttamente. –

Problemi correlati