5

Sto costruendo un sistema di reporting delle metriche su una flotta di istanze contenente oltre 100.000 istanze front-end. Per ogni richiesta, ogni singola istanza avrà un tempo di risposta. E quello di cui ho bisogno è la distribuzione dei tempi di risposta di ogni tipo di richiesta sull'intera flotta. Ad esempio [Percentile 50, Percentile 90, Percentile 99, Percentile 99,9 ...] di [requestType1, requestType2 ... requestType1000].Come calcolare la distribuzione (istogramma) di grandi quantità di dati in un sistema distribuito?

Ogni istanza raccoglierà il tempo di risposta all'interno. Quindi, più di un minuto, ciò che un'istanza raccoglie in memoria è l'elenco dei tempi di risposta di tutti i tipi di requestTypes. Ad esempio requestType1 - [1, 2, 3, 4, 1, 2], requestType2 - [2, 2, 3, 2, 1] ...... Quindi quello che devo fare è elaborare questi dati e produrre il risultato finale.

Ho provato un sacco di disegni, i miei principali punti dolenti sono l'enorme dimensione dei punti dati che ho raccolto di ogni singola requestType, e le spese di comunicazione tra le istanze. Di seguito spiegherò il mio progetto attuale, ma voglio anche sapere se ci sono progetti migliori o alcuni algoritmi elaborati possono aggregare gli istogrammi?

Attualmente il più promettente è come: Ogni istanza di front-end invierà i propri dati a un'istanza casuale di una flotta di istanze di livello intermedio. In questa flotta di medio livello, ogni istanza aggregherà tutti i punti dati che ottiene in un breve periodo di tempo, ad es. 5 secondi. (Non ha abbastanza memoria da tenere a lungo). Quindi l'istanza di livello intermedio distribuirà i dati aggregati per valore hash di requestTypes alle istanze back-end. Ciò significa che tutte le istanze di livello intermedio invieranno i punti di accesso degli stessi requestTypes alla stessa istanza di back-end. Quindi nell'istanza di back-end potrei usare il contenitore dell'istogramma di una terza parte (istogramma di CodaHale o HdrHistogram) per calcolare P50, P90, P99 dei datapoint in arrivo ... Il motivo per cui ho bisogno della flotta di istanze di medio livello è l'invio di dati da front-end le istanze finali sono costose, quindi voglio che vengano inviati tutti i dati contemporaneamente, ma non effettuare 100 chiamate da inviare a 100 diverse istanze di back-end.

Il problema principale che posso pensare a questo disegno è la complessità relativamente elevata e, se una back-instance non funziona, potrei perdere tutti i dati di alcuni RequestTypes. Quindi, per la parte di progettazione del sistema, qualcuno ha delle idee migliori?

L'altro modo in cui penso è trovare un algoritmo elaborato per aggregare gli istogrammi esistenti. Il disegno sopra, i dati che ottengo saranno accurati al 100%. Ma in realtà posso tollerare alcuni errori. Ad esempio, nell'istogramma di CodaHale e nell'HdrHistogram, sono sicuro che in realtà non salvano tutti i punti di dati, ma hanno applicato alcuni algoritmi matematici avanzati per ottenere un risultato di precisione relativamente alta a costi molto bassi. E posso usare la libreria Istogramma nelle istanze front-end o mid-layer. Ma i problemi sono anche se riesco a ottenere [P50, P90, P99 ...] di ogni istanza front-end o istanza mid-layer a basso costo, non sono riuscito a trovare un modo per aggregarli. Poiché un'istanza di front-end diversa può gestire diversi tipi di richieste e la distribuzione delle richieste alle istanze front-end non è nota, è sufficiente calcolare il valore medio di ALL P50, P90, P99 avrà molta imprecisione. Quindi qualcuno ha idea, come posso aggregare più istogrammi di CodaHale o HdrHistogram insieme? O ci sono algoritmi che possono aiutare ad aggregare gli istogrammi in uno?

======================================== ============

Ho qualche idea nuova la scorsa notte. Poiché P50 e P90 misurano la "media" di tutti i dati, penso che applicare la media ponderata su tutti i P50 e P90 calcolati in ogni istanza di medio livello dovrebbe essere abbastanza buono. Ma P99, P99.9 e P99.99 stanno misurando quei dati periferici, quindi una media di P99 di sottoinsieme potrebbe non essere accurata.

Ma se si assume che i dati nell'istanza di livello intermedio siano distribuiti in maniera relativamente casuale, è possibile ottenere il 5% più alto dei punti dati in ogni istanza di livello medio e inviarli al back-end. Il 5% di tutti i datapoint di medio livello insieme rappresenta il 5% dei punti dati globali. E ho più fiducia che il P80 di questi dati del 5% è vicino al P99 dei dati complessivi, P98 di questi dati del 5% è vicino a P99.9 dei dati complessivi, e P99.8 del 5% dei dati è vicino a P99.9 .99 di dati complessivi.

Spero che in questo modo, posso solo trasferire il 5% dei dati complessivi, ma ottenere un risultato di alta precisione. Cosa ne pensi di questo modo? disegno

+0

È affermare che 'Per qualsiasi richiesta, ogni singola istanza avrà una time.' risposta che suona per me come ogni istanza gestirà ogni singola richiesta che si trasmette, ma in seguito dirai: 'Perché diverse istanze front-end possono gestire diversi tipi di richieste e la distribuzione delle richieste alle istanze front-end è sconosciuta [...]' che implica qualcos'altro. Potresti spiegare un po 'di più come funziona la gestione delle richieste? –

+1

Inoltre, ottieni effettivamente i tempi di risposta come numeri interi (o stai arrotondando ai numeri interi)? Questo suggerirebbe che (usando il conteggio sort o qualcosa di simile) e codificare i dati con RLE dovrebbe velocizzare la comunicazione un po '. –

+0

Quando una richiesta viene effettuata alla flotta front-end, il sistema sceglierà un'istanza per gestire la richiesta. È una scatola nera, quindi non so quale istanza gestirà la richiesta. Ma di sicuro c'è una sola e unica istanza per gestire una richiesta. –

risposta

1

Sistema:

Se le chiamate sono costosi, allora forse si potrebbe streaming i dati? Nella tua descrizione non vedo i reali vantaggi di questo livello intermedio: perché frontend-> il costo medio delle chiamate è inferiore al frontend-> backend?

Se siete preoccupati di perdere dati che si hanno due opzioni:

  • inviare eventi a più nodi. Ma dovrai in qualche modo evitare la duplicazione durante l'elaborazione.
  • scrivere tutto a un log persistente (Kafka potrebbe fare il lavoro qui)

Tutto dipende dal volume di eventi (1/min/frontend o 10k/s/frontend) e la distanza tra il frontend e il back-end (stesso datacenter o dispositivi mobili -> datacenter?).

Se è lo stesso datacenter che è possibile comunicare con il back-end tramite log persistente, risolve il problema di perdita di dati. Se ci sono un sacco di eventi li si poteva aggregate sul frontend e spingere aggregati a valle

Aggregazione:

Ci sono vari algoritmi, ad esempio q-digest, t-digest. Vedere Quantiles over Data Streams: An Experimental Study

E 'anche interessante notare che HdrHistograms can be combined