Best practice per Heartbeat in sistemi distribuiti

5

Nel nostro sistema avevamo in passato un fornitore di dati esterni (chiamiamolo sorgente) che inviava heartbeat regolari a un'applicazione java (chiamalo client). Se l'heartbeat non è riuscito, il sistema si è spento (per evitare di servire dati obsoleti in un'applicazione critica). Questo è stato semplice in quanto sia i dati che l'heartbeat utilizzavano lo stesso canale, rendendolo altamente affidabile.

Da allora ci siamo spostati su un sistema distribuito con client java suddivisi in diversi microservizi e dati che scorrevano in parte attraverso le code kafka tra i servizi.

La cosa importante - il sistema più a monte (chiamalo destinazione) dovrebbe comunque ricevere in modo affidabile un battito cardiaco.

Se continuiamo a inviare l'heartbeat tramite un canale separato, qualsiasi guasto in uno dei microservices o nella coda di kafka interromperà il flusso di dati verso la destinazione, d'altra parte, l'heartbeat continuerà a scorrere senza interruzioni - in caso contrario scopo completo di avere un battito cardiaco

Una delle soluzioni a cui sto pensando è quella di spingere gli heartbeat attraverso tutti i servizi e le code di kafka in modo che prendano lo stesso percorso dei dati stessi. In ogni caso, quali sono i migliori modelli / criteri di progettazione per reimplementare l'heartbeat in un sistema così distribuito?

    
posta senseiwu 06.04.2018 - 12:00
fonte

3 risposte

4

La tua soluzione è ovvia. Quando ogni servizio riceve un heartbeat da una delle sue fonti, annota l'origine e l'ora e quando quel servizio invierà un heartbeat (ai suoi sink), controlla che tutte le sue fonti siano vere.

Se disponi di fonti opzionali, il "sono le mie fonti vere" diventa più complicato, ma probabilmente lo hai trattato nel modo in cui gestisce i dati, l'heartbeat deve solo corrispondere a tale approccio.

Se ServiceA può inviare dati a una delle 3 istanze di ServiceB , deve inviare heartbeat a tutte e 3 le istanze .

Se ServiceC riceve dati da una qualsiasi delle 3 istanze di ServiceD , ha visto un recente heartbeat dalla sua sorgente D se qualsiasi ServiceD ha inviato uno

    
risposta data 06.04.2018 - 12:10
fonte
1

OK così. Come ho capito, hai questo:

DataSource - pushes occasional messages to Clients

Client - Listens for datasource messages

Problema: poiché DataSource invia messaggi in modo intermittente, se muore i client rimangono inconsapevoli e continuano a visualizzare i dati vecchi e ora non validi.

Soluzione precedente:

DataSource - pushes occasional messages to Clients, 
    PLUS a regular small 'heartbeat' message

Client - Listens for DataSource messages and the 'heartbeat'. 
    If the heartbeat isn't received X seconds after the last one, 
    we know the DataSource has died and can take action.

Nuova situazione:

DataSource - pushes occasional messages to intermediate clients,

Load Balanced MicroService(1) - listens for datasource mesages 
    and pushes messages to next in chain

Load Balanced MicroService(n) - listens for MicroService(n-1) 
    and pushes messages to next in chain

Client - Listens for MicroService(last) messages, but the
    heartbeat is lost in the ether

Soluzione:

I MicroServices dovrebbero comportarsi come il vecchio client e segnalare quando la loro origine dati non è riuscita ai loro ascoltatori.

Ma mentre i messaggi verranno elaborati da un singolo microservizio in un gruppo con bilanciamento del carico, il battito cardiaco deve essere elaborato da tutti loro. Pertanto, l'heartbeat deve utilizzare il routing fanout mentre il messaggio deve utilizzare una coda worker .

Tuttavia, è difficile continuare questo schema lungo la catena poiché ogni processo di lavoro pubblicherebbe il proprio battito cardiaco.

Suggerirei una forma più avanzata di routing dove hai un servizio di routing che nasconde i lavoratori dal resto del mondo

Qui l'operatore del router ascolta le code in entrata e distribuisce le attività a un pool di lavoratori. Riceve il lavoro completato e lo trasmette. Nascondere i singoli lavoratori. Può far fronte a lavoratori che muoiono o impiegano troppo tempo per completare il lavoro, licenziare nuovi lavoratori quando sono sotto carico ecc.

Nel tuo caso può anche gestire il battito cardiaco. assicurando che l'heartbeat downstream sia rappresentativo dei messaggi che sta inviando.

    
risposta data 06.04.2018 - 16:33
fonte
0

Un "battito cardiaco" è la soluzione del problema sbagliato.

Il consumatore dei microservizi deve fare in modo di non servire dati obsoleti quando uno dei servizi di microservizio si interrompe.

In effetti, un battito cardiaco, anche nella configurazione corrente, non risolve il problema.

Se il database non funziona, un "heartbeat" che non si connette al database segnalerà che l'applicazione è ancora attiva. Mi sono imbattuto in questo diversi anni fa. Peggio ancora, non si può presumere che ogni micro servizio si connetta allo stesso database.

Ogni singola chiamata a un micro servizio richiede la gestione degli errori per qualsiasi problema catastrofico che può verificarsi dal momento in cui si effettua la chiamata (fonte) a tutte le risorse utilizzate dal micro servizio. Ovviamente non è possibile stabilire se il database per un micro servizio è inattivo quando è necessario chiamarlo, ma verrà restituita una sorta di risposta all'errore HTTP (4xx o 5xx). E quando le risposte non tornano, le applicazioni che consumano i microservizi necessitano di timeout sensibili attorno alle chiamate.

L'ultima parte del puzzle è un buon monitoraggio server dell'intero ecosistema tecnologico e un mezzo ben definito ed efficiente per informare le persone responsabili del mantenimento dei problemi dei micro servizi da parte dei consumatori.

Benvenuti nell'architettura orientata al servizio / micro-servizio. Le cose funzionano alla grande quando funzionano, ma quando regna il caos, si riversa.

    
risposta data 06.04.2018 - 18:15
fonte

Leggi altre domande sui tag