design dell'applicazione distribuita - utilizzando il broker dei messaggi

4

Sfondo

Sto provando a progettare un layer / componente nella mia applicazione distribuita che comunicherà tra il componente A e il componente B.

In questo momento, questa "comunicazione" si realizza replicando un intero database dal server in cui il componente A vive sopra al componente B. Ma questo progetto si è rivelato molto fragile e troppo strettamente accoppiato. Voglio raccomandare al team di passare a una soluzione di messaggistica in cui A notifica a B un cambiamento di stato dei dati.

Domande

Ma ecco la domanda. A seconda della dimensione dei dati, posso

  1. invia i dati come parte del carico utile del messaggio,
  2. o semplicemente notifica a B che c'è qualcosa da fare a B / da afferrare.

Chiaramente, l'opzione 1 è più semplice perché non ho bisogno di scrivere troppo codice nella mia logica di sottoscrizione. Tuttavia, la realtà è che a volte (non troppo spesso) la dimensione dei dati può superare la dimensione massima consentita del messaggio. (userò mqtt per avviare il mio prototipo che come dimensione massima del carico utile di 268435455 byte)

Per quanto riguarda il design, mi rendo conto che è meglio per ogni servizio / componente (A e B) essere autonomo ... e semplicemente "sapere" cosa deve fare quando riceve un messaggio. Ma in termini pratici, cosa significa?

Ad esempio, considera questo caso d'uso:

"A" pubblica un messaggio che un nuovo widget è appena stato creato nel suo database. "B" è un abbonato sul canale "widget". Ottiene il messaggio che include quanto segue:

- action:CREATE
- widgetID: 123

Per ottenere i dati sul widget, dovrebbe B:

  • chiama un'API REST in esecuzione sul server A?

    ad es. link

  • essere in grado di catturare i dati del widget dal payload del messaggio?

Altre domande potrebbero includere:

  • quando dovrei considerare che il broker dei messaggi abbia successo? Quando viene consegnato il messaggio? O quando B ha una copia dei dati in questione?
  • qualche buon articolo che sai di quello che posso leggere per aiutarti con questo tipo di design?
  • che dire se ho appena evitato di inviare messaggi tutti insieme ... e ho scritto un'interfaccia CRUD per il componente B? "A" chiamerebbe l'interfaccia CRUD ogni volta che veniva modificato un widget. qual è il vantaggio di utilizzare il broker dei messaggi su questo tipo di soluzione?
posta dot 20.06.2017 - 17:52
fonte

1 risposta

2

Prima alcune realtà di base delle code:

Le code sono uno strumento potente ma introducono anche complessità. La cosa più importante da risolvere è che cosa succede se un messaggio in una coda non viene gestito correttamente. Un'implementazione ingenua leggerà dalla coda, commetterà (ed eliminerà il messaggio) e quindi tenterà di elaborare. Se si verifica un errore, il messaggio è sparito. Puoi effettivamente utilizzare questo approccio se non è cruciale che ogni messaggio venga elaborato. Ad esempio, se si dispone di un libro mastro di tutte le cose che sono necessarie ed è OK pulire periodicamente. Se devi elaborare ogni messaggio in ordine, questo è un grosso problema.

Puoi anche rifiutare di salvare il messaggio dalla coda finché non lo hai elaborato con successo. Questo è più robusto ma c'è un problema di messaggi velenosi . Se esegui semplicemente il rollback in caso di errore, puoi finire in un ciclo infinito di lettura dello stesso messaggio dalla coda. Nel frattempo più messaggi si accumulano e alla fine ka-blammo! Questo accadrà nel bel mezzo della notte mentre stai cavalcando un unicorno attraverso la foresta di lecca-lecca. Quindi hai bisogno di gestione dei messaggi avvelenati. Ma se ti viene richiesto di elaborare ogni messaggio in ordine, questo non è ancora di aiuto.

Non è chiaro se vuoi code o argomenti. Uno dei punti di forza di Kafka è che non devi scegliere perché un'astrazione copre entrambi gli approcci. Nelle piattaforme di accodamento standard devi decidere in anticipo, possibilmente prima di capire veramente il problema.

Direi che il pattern in 2 è molto più robusto. Quello che probabilmente farei è rendere l'interfaccia riposante in grado di fornire tutti gli eventi che non sono stati elaborati (per lo meno.) Ad esempio, se può vedere l'evento precedente su quello corrente, il ricevitore saprà se è elaborazione fuori servizio.  Quindi, se un messaggio o due non vengono gestiti, non è un grosso problema. Attendi il prossimo messaggio o imponi un aggiornamento.

La risposta più rigorosa per quando considerare il messaggio consegnato è quando è stato commesso. Se vuoi davvero fare questo il "modo giusto", usi commit a 2 fasi . Questa roba è davvero solida, ma può anche essere un po 'complicata da configurare. La mia preferenza sarebbe per la costruzione di sistemi affidabili che funzionano quando i componenti sono inaffidabili a differenza dell'affidabilità di cose come l'infrastruttura di accodamento. Se ciò sembra strano, considera che TCP (affidabile) è costruito su UDP (inaffidabile).

Non conosco un articolo specifico, ma se non hai visitato questo sito , dovresti iniziare da lì.

Non sono sicuro di cosa intendi per "broker dei messaggi" qui poiché tutto ciò che abbiamo discusso finora è una semplice coda. Esiste un modello broker dei messaggi ma non credo che questo sia valido. Direi che le code sono utili nelle situazioni in cui si sta elaborando il lavoro in modo asincrono, soprattutto quando si desidera distribuire il carico su un numero di sistemi che consumano. Anche quando queste condizioni sono soddisfatte, vorrei attenermi a piccoli messaggi. Nella mia esperienza, cercare di inviare grandi quantità di dati sulle code non è stata una strategia vincente. Non proverei di nuovo. La 'messaggistica affidabile' dell'IMO è un termine improprio e quindi la 'consegna garantita'.

La tua idea di avere un'API su B che le chiamate A potrebbero funzionare, ma cosa succede se B non può essere raggiunto al momento o soffoca sulla chiamata (ad esempio, troppo volume)? Un grande vantaggio di una coda è che può fungere da grande buffer con storage indipendente. A non dipende da B per mettere i messaggi in coda. B può essere chiuso e i messaggi verranno trattenuti finché non sarà pronto a gestirli. Naturalmente, il sistema di accodamento potrebbe non essere disponibile, motivo per cui è necessario che sia molto robusto. Questi sono di nuovo i motivi per evitare grandi messaggi. Più piccoli sono i messaggi, più facile (e meno costoso) è memorizzarne più a lungo. Anche i messaggi di grandi dimensioni sono più propensi a creare problemi con il sistema di accodamento.

    
risposta data 20.06.2017 - 18:20
fonte

Leggi altre domande sui tag