Contesto
Stiamo costruendo un'applicazione che si comporta come un hub per i messaggi provenienti da più produttori e che assegna ai consumatori in base a determinati criteri.
È necessario che il design sia altamente scalabile, ma allo stesso tempo, le funzionalità principali della correlazione messaggio-interazione non dovrebbero essere interrotte.
Principali entità nel sistema:
Produttore (pronuncia P1 in questo esempio): entità che avvia un'interazione con un consumatore (tuttavia il produttore non può scegliere in modo esplicito a quale consumatore può parlare)
Consumatore (pronuncia C1 in questo esempio): entità che serve richieste come richiesto dal Prodcuer.
Interazione (dire I1 in questo esempio): è un contenitore logico per i messaggi scambiati tra P1 e C1
Messaggio : un pacchetto di informazioni da inviare all'altro interlocutore. Sia P1 che C1 possono generare un messaggio da inviare all'altro interlocutore. Per questo esempio, prendiamo uno scenario di un'interazione di 3 messaggi in ordine cronologico M1 - > Primo messaggio in I1 creato da P1 M2 - > Secondo messaggio in I1 creato da C1 in risposta a M1 M3 - > Terzo messaggio in I1 creato da P1 in risposta a M2
Ogni volta che un Prodcuer invia un messaggio, il produttore deve inviare l'ID di interazione nell'intestazione del messaggio in modo che i messaggi dei produttori vengano indirizzati allo stesso Consumatore che ha il contesto. Esempio: Quando P1 invia M3, deve specificare I1 nel payload, in modo che M3 sia correttamente indirizzato a C1.
Se P1 non fornisce I1 nel messaggio M3, M3 verrà trattato come un nuovo messaggio e quindi una nuova interazione. Ciò causerà alla M3 di creare una nuova Interaction Say Ix e atterrare con un diverso Consumer (Say Cn)
Al punto di accesso dell'applicazione è un gateway API che espone un formato di immissione dei messaggi comune e accetta i payload JSON. Ogni volta che un messaggio (Say M) viene ricevuto nell'API viene eseguita la seguente logica di co-relazione (percorso felice)
IF (M.referenceId == null)
{
Create a new Interaction //I1
Find a Consumer from a list of consumers who is free. //C1
Assign the interaction to the Consumer //Assign I1 to C1
}
Else IF (M.referenceId != null)
{
Check in application database IF an interaction with this ID exists. //check I1.id = M.referenceId
If an interaction is found, associate M with the interaction
Find the Consumer already associated with the interaction and deliver the message.
}
Ecco come apparirebbe il DB
|| ID messaggio || Creato da || Consegnato a || ID interazione ||
| M1 | P1 | C1 | I1 |
| M2 | C1 | P1 | I1 |
| M3 | P1 | C1 | I1 |
Dichiarazione di problemi: Vogliamo utilizzare una coda per essere in grado di scalare pesantemente, ma la nostra operazione principale richiede l'accesso al DB. Dobbiamo scegliere tra 2 possibili approcci.
Approccio # 1: Il flusso delle chiamate è simile a questo: Gateway API < - > Kafka Queue < - > NoSQL-DB (o RDBMS per quella materia)
Pro: 1. Consente una buona messa in coda, Contro: Poiché la logica di co-relazione non è stata eseguita, non possiamo correlare il messaggio e quindi non possiamo dire al produttore quale sia l'ID di interazione
Approccio # 2: Il flusso delle chiamate è simile a questo: Gateway API < - > NoSQLDB (o RDBMS per quella materia)
Pro: Permette alla logica di correlazione di funzionare e quindi possiamo fornire in modo affidabile l'ID di interazione al produttore.
Contro: non può utilizzare la potenza di Kafka
Domanda : Esiste un approccio che possa facilitare la potenza di Kafka ma allo stesso tempo ci consenta di fare la logica di ricerca del DB senza causare alcun rallentamento?