Architettura del server per brevi burst di ~ 150 subquery paralleli CPU-heavy

6

Il client invia una query (alcune centinaia di caratteri) al servizio web. Questa query può essere suddivisa in 20 a 150 sottoquery con un'espressione regolare. Quelle sottoquery possono quindi essere calcolate indipendentemente e prendere ciascuna fino a 5 secondi. Pertanto vorremmo che queste subquery funzionassero in parallelo affinché la query originale potesse tornare rapidamente.

Ha senso impostare una funzione Amazon Lambda per la sottoquery, metterla dietro un gateway HTTP e quindi disporre di un piccolo server delle applicazioni in attesa che tutte le subquery finiscano, integrarle e inviarle al client? O faremo meglio a pubblicare fino a 150 thread su un'istanza pesante EC2?

Vogliamo che il servizio sia scalabile facilmente, ma non aspettatevi molti utenti all'inizio. Tuttavia, per quegli utenti la query dovrebbe essere completata con ~ 5 secondi.

Nota: AWS non è un requisito, lo sto solo utilizzando come esempio.

    
posta mb21 10.10.2016 - 12:03
fonte

3 risposte

6

Poiché la CPU è limitata, è necessario mettere le mani su 150 core CPU, uno per ogni thread. Questo esclude un singolo server, dal momento che un server di tali proporzioni sarebbe eccessivamente costoso - e non ne hai davvero bisogno.

La tua architettura generale con un frontend comune che distribuisce il lavoro a più lavoratori e combina i loro risultati sembra essere ragionevole. Dovrai fare alcuni calcoli per trovare la soluzione più economica per ottenere molte CPU. Ciò tende a puntare su AWS Lambda in quanto richiede solo calcoli a raffica, ma potrebbe venire con restrizioni. Quanti Lambdas possono eseguire contemporaneamente? 150 allo stesso tempo è molto. Quali lingue puoi usare; puoi ridurre i costi utilizzando il codice nativo ottimizzato? Soprattutto, non penso che Amazon crei garanzie specifiche sulle prestazioni per quel prodotto, mentre tu hai più controllo sulla CPU fisica con tipi di istanze più tradizionali.

E le prestazioni effettive della CPU sono importanti per te. Mentre sei disposto a uccidere il calcolo dopo 5 secondi, la quantità di calcolo eseguita fino a quel momento potrebbe variare in modo selvaggio. Probabilmente riuscirai a ottenere 150 core in modo piuttosto economico eseguendo un cluster Beowulf di schede Raspberry Pi nella tua cantina, ma ciò non è da remoto paragonabile alla potenza di calcolo di cinque server Intel Xeon di fascia alta.

È quindi importante definire chiaramente gli obiettivi di rendimento e uno SLA e quindi testare una soluzione proposta. Dovrai anche pensare a richieste simultanee. Data l'elevata quantità di calcoli per richiesta del cliente, potrebbe essere meglio elaborare le richieste client in modo sequenziale se ciò è accettabile per i client. Ma questo mette anche un limite superiore ai client che puoi supportare, poiché la probabilità che un client debba attendere prima che la richiesta possa essere elaborata cresce piuttosto rapidamente (in relazione al paradosso del compleanno).

Questo è un problema di scalabilità. È possibile ritardare la pianificazione pianificando le richieste del client per evitare richieste simultanee o ottenere la capacità di gestire più richieste in parallelo. Questo a sua volta può essere gestito lanciando più denaro / server al problema, o tramite l'ottimizzazione delle prestazioni dell'algoritmo. Per esempio. Ho visto un caso in cui un programma Python potrebbe essere reso 3 × più veloce da ottimizzazioni guidate da profili come l'estrazione di un accesso di attributo di istanza da un ciclo molto stretto. Le maggiori vincite derivano sempre dalla riduzione della complessità algoritmica, se possibile.

    
risposta data 10.10.2016 - 17:34
fonte
2

Disegnerei la mia interfaccia e il mio task master secondo due presupposti:

  • La potenza di elaborazione è distribuita
  • Non ho sempre abbastanza potenza di elaborazione disponibile

Se i lavori sono intrinsecamente lunghi e il client / l'utente finale lo sa, la mia preferenza è di rendere il master delle operazioni rispettoso delle attività "concorrenti". Preferisco le notifiche di avanzamento e i meccanismi per le cancellazioni avviate dal cliente su un servizio "lunatico" che semplicemente "si arrende" quando ne ha voglia. I limiti di tempo dovrebbero essere orientati a fermare le richieste che in realtà non stanno facendo progressi; non solo richieste lunghe che il cliente potrebbe desiderare di aspettare.

Considera anche che, anche se ho 150 CPU (distribuite o meno), ma a volte capita anche di ricevere 2 richieste simultanee, le richieste inizieranno a fallire. E i miei clienti non saranno felici se i loro lavori iniziano a fallire "perché qualcun altro stava anche utilizzando il servizio."

E proprio da una prospettiva di sviluppo pragmatica, voglio essere piuttosto agnostico sull'ambiente di hosting. Sarà più facile codificare il lavoro distribuito in primo piano di quello che sarà in più tardi decidere di distribuire il lavoro che dipende dai thread, ed eventualmente anche stato condiviso (o qualsiasi altra cosa).

... D'altra parte, se il cliente si aspetta che queste richieste siano veloci , puoi concentrarti sulla cosa sbagliata qui! Potrebbe essere necessario cercare prima le ottimizzazioni, il caching e l'euristica. (A meno che veramente voglia acquistare e gestire ~ 150 CPU per richiesta simultanea.)

    
risposta data 10.10.2016 - 19:05
fonte
0

È difficile scalare con un elevato utilizzo di CPU o IO.

Nella mia esperienza personale, per scalare devi capire meglio il problema e cercare di risolvere nel miglior modo possibile.
Ad esempio, puoi provare ad archiviare alcuni risultati in modo che il server non debba calcolare tutti i risultati. Questo è molto semplice da implementare e di solito si salvano alcuni cicli della CPU.
Il Regex è uno strumento molto potente ma con un grande costo per la CPU. Alcuni db o server possono estendersi con codice nativo, puoi provare a cambiare la regex in codice nativo, ma questo codice diventa nativo e più complicato da gestire.
Puoi provare a tradurre la regex in query più semplici e misurare le prestazioni.
Un'altra possibile soluzione è passare una tabella temporanea, in modo da poter ridurre i numeri della riga prima di utilizzare la funzione regex.

    
risposta data 10.10.2016 - 19:07
fonte

Leggi altre domande sui tag