Come garantire il recapito dei messaggi HTTP in modo fault tolerant

0

Quando un'applicazione A comunica con un sistema B esterno / di terze parti, c'è sempre la possibilità che B sia inattivo.

Diciamo che A genera un evento che dovrebbe essere inviato come messaggio a B via HTTP, qual è il modo migliore per garantire che il messaggio sia consegnato?

Una possibilità è ovviamente quella di avere qualche logica di riprovare per inviare nuovamente il messaggio alcune volte. Ma cosa dovremmo fare con il messaggio se la consegna fallisce troppe volte? O se A si blocca (forse a causa di troppi messaggi in attesa di essere inviati)? Quindi abbiamo bisogno di un modo per mantenere quei messaggi per poter riprendere il recapito dei messaggi dopo che A ha recuperato.

La mia prima idea era quella di archiviare tutti gli eventi in una tabella dedicata nel database e contrassegnarli quando vengono inviati. Quindi un collega ha sostenuto che non possiamo sempre fare affidamento sul database e dovremmo invece archiviare i messaggi localmente sul filesystem. Ma il secondo approccio sembra che implementeremo un messaggio in coda e saremmo migliori con una vera e propria coda di messaggi (che al momento non abbiamo per questa applicazione).

Lo stesso collega ha poi sostenuto che anche se abbiamo una coda di messaggi, non possiamo essere sicuri che il messaggio sia consegnato alla coda e avremmo ancora bisogno di implementare una coda sul filesystem. Mi sembra davvero eccessivo. Ciò significherebbe che per essere veramente sicuri dobbiamo implementare una coda di messaggi memorizzata localmente per tutte le comunicazioni anche tra i nostri microservizi diversi.

Per contesto questo è un volume basso con un sistema con pochi messaggi (al massimo negli anni '100) al giorno, ma hanno un valore molto alto (usato per la fatturazione) in modo che non vogliamo perdere nessuno.

Qualche idea?

    
posta bangnab 11.10.2018 - 10:16
fonte

4 risposte

2

La soluzione di database è in definitiva il migliore, il filesystem transazionale non è comune, a meno che non si consideri che il filesystem non fallisce mai (impostazioni di autorizzazione, disco pieno, ...).

Descriverò in dettaglio uno scenario più accurato di ciò che suggerisci per assicurarti di non perdere una voce, utilizzando le transazioni.

Quando è necessario inviare qualcosa:

  1. Crea una voce persistente con stato "in sospeso" e un link ai dati che devi inviare.
  2. Prova a inviarlo, se fallisce, lascialo al pendingstatus, altrimenti aggiorna lo stato a "finito".
  3. Conferma la transazione corrente
  4. Avere un assistente in background dedicato per verificare l'invio di materiale in sospeso e provare a inviarlo. Alla fine, prima di provare a inviarli, l'operatore può provare a verificare se il servizio di terze parti è disponibile. Aprire una transazione per ciascun messaggio per inviarli e aggiornarli indipendentemente. Assicurati che un errore sul messaggio non fallisca l'invio di altri (prendi eccezioni). Al termine, aggiorna lo stato a "finito".

Questo funziona anche per compiti come spingere un file su un server ftp.

Se l'ordine è importante, il flusso di lavoro è più semplice: non tentare mai di inviare un messaggio, per giustificarlo accodandolo aggiungendo una voce che deve occupare l'operatore in background. E se un messaggio fallisce, non provare a mandarne altri. Quindi la tua tabella è una coda bloccante di attività da fare.

    
risposta data 11.10.2018 - 10:31
fonte
2

Il tuo collega ha ragione. Non è possibile eliminare le tutte modalità di errore. L'obiettivo dovrebbe essere prevedibile modalità di errore, ad es. per soddisfare un certo SLA è possibile che si desideri un'affidabilità del 99,99% e un tempo di risposta inferiore a 24 ore in caso di guasto totale, quel genere di cose.

Per raggiungere un obiettivo del genere, molte organizzazioni sceglieranno una piattaforma comprovata (ad esempio MSMQ o anche solo SMTP). Il vantaggio di una piattaforma comprovata è che è stato accuratamente testato sia in laboratorio che sul mercato e la gente sa praticamente cosa fa quando le cose vanno male. Generalmente vengono forniti con la scelta di archiviazione permanente, oltre a cose importanti a cui non si pensava come il monitoraggio della coda, i contatori delle prestazioni, la limitazione e gli avvisi via email / SMS per il proprio team operativo. Inoltre, ci sarà una community di utenti, e possibilmente articoli tecnici su come configurarlo con hot standby, disaster recovery, second-siting, ecc. Potrebbe anche essere disponibile come offerta di servizi dal tuo provider cloud.

Se non lavori per un'organizzazione la cui competenza principale sono i protocolli di messaggistica, probabilmente stai meglio indagando su opzioni di terze parti piuttosto che coltivarle da sole. In questo modo puoi dedicare più tempo al tuo core business.

    
risposta data 11.10.2018 - 11:18
fonte
0

IMHO, sia l'approccio del database che del filesystem per i messaggi in coda vanno bene.

Entrambi ti salveranno in caso di riavvio, arresto anomalo o disconnessione del processo.

Tuttavia, anche se questo copre la maggior parte degli incidenti, non protegge da "disastri". Per "disastro", intendo una macchina non recuperabile per qualsiasi motivo. È estremamente raro, ma potrebbe succedere. Un buon modo per proteggersi da questo è avere nodi ridondanti , così che quando uno è morto, il sistema nel suo insieme continua a funzionare. Tuttavia, questo porta con sé molte altre sfide.

    
risposta data 11.10.2018 - 17:39
fonte
0

Come hanno già detto altre risposte, il filesystem locale non è sempre disponibile. Se hai davvero bisogno di una consegna affidabile in tutte le circostanze possibili, sei fregato.

Tuttavia, in realtà non è necessario garantire la consegna in tutte le circostanze. Hai davvero bisogno di consegnare una fattura solo se l'ordine stesso è stato creato con successo. Infatti, se la creazione dell'ordine non è riuscita, probabilmente non si desidera inviare una fattura.

Ciò porta alla conseguenza che qualsiasi cosa tu faccia, devi finalizzare gli ordini di acquisto e il piano di consegna delle fatture in modo che si assicuri che siano persi con successo insieme o falliscano insieme .

Se memorizzi il tuo ordine di acquisto in un database, dovresti utilizzare la stessa transazione del database per mantenere il piano di consegna delle fatture in modo atomico.

Se si utilizza una coda di messaggi, è necessario mettere in coda l'ordine e il recapito della fattura nella coda dei messaggi, atomicamente; questo significherebbe anche che la tua coda di messaggi diventerebbe la fonte della verità per quanto riguarda il successo e gli ordini.

Il filesystem è un po 'complicato. In realtà non penso che ci sia un singolo scenario in cui la memorizzazione nel filesystem sarebbe la soluzione migliore. Trasformare un filesystem in un sistema transazionale non è un compito banale nella maggior parte dei file system.

    
risposta data 12.10.2018 - 05:08
fonte