Prima di rispondere a "uno scambio, o molti?" domanda. In realtà voglio fare un'altra domanda: abbiamo davvero bisogno di uno scambio personalizzato per questo caso?
Diversi tipi di eventi oggetto sono così nativi da corrispondere a diversi tipi di messaggi da pubblicare, ma a volte non è veramente necessario.Cosa succede se estraiamo tutti i 3 tipi di eventi come un evento di "scrittura", i cui sotto-tipi sono "creati", "aggiornati" e "cancellati"?
| object | event | sub-type |
|-----------------------------|
| user | write | created |
| user | write | updated |
| user | write | deleted |
Soluzione 1
La soluzione più semplice per sostenere questa è solo potessimo progettare una coda “user.write”, e pubblicare tutti i messaggi di evento utente scrittura a questa coda direttamente attraverso lo scambio di default globale . Quando si pubblica direttamente su una coda, la limitazione più grande è che si presume che solo un'app sia abbonata a questo tipo di messaggi. Anche più istanze di un'app che si iscrive a questa coda va bene.
| queue | app |
|-------------------|
| user.write | app1 |
Soluzione 2
La soluzione più semplice non poteva funziona quando c'è una seconda app (con logica di elaborazione diversa) utile per iscriversi a eventuali messaggi pubblicati alla coda. Quando ci sono più app che sottoscrivono, abbiamo almeno bisogno di uno scambio di tipo "fanout" con associazioni a più code. In modo che i messaggi vengano pubblicati su excahnge e lo scambio duplica i messaggi su ciascuna coda. Ogni coda rappresenta il processo di elaborazione di ogni diversa app.
| queue | subscriber |
|-------------------------------|
| user.write.app1 | app1 |
| user.write.app2 | app2 |
| exchange | type | binding_queue |
|---------------------------------------|
| user.write | fanout | user.write.app1 |
| user.write | fanout | user.write.app2 |
Questa seconda soluzione funziona bene se ogni abbonato fa a cuore e vogliono gestire tutti i sottotipi di eventi “user.write”, o almeno per esporre tutti questi eventi sub-tipo per ogni abbonati non è un problema. Ad esempio, se l'app dell'abbonato è semplicemente per mantenere il registro di trascrizione; o anche se l'utente gestisce solo user.created, è opportuno informarlo quando avviene user.updated o user.deleted. Diventa meno elegante quando alcuni abbonati provengono dall'esterno della propria organizzazione e si desidera solo notificarli in merito a eventi specifici del sottotipo. Ad esempio, se app2 vuole solo gestire user.created e non dovrebbe avere la conoscenza di user.updated o user.deleted.
Soluzione 3
Per risolvere il problema di cui sopra, dobbiamo estrarre concetto di “creato dall'utente” da “user.write”. Il tipo di scambio "argomento" potrebbe aiutare. Quando pubblichiamo i messaggi, usiamo user.created/user.updated/user.deleted come chiavi di routing, in modo da poter impostare la chiave di associazione della coda "user.write.app1" essere "utente. *" E la chiave di associazione di La coda "user.created.app2" è "user.created".
| queue | subscriber |
|---------------------------------|
| user.write.app1 | app1 |
| user.created.app2 | app2 |
| exchange | type | binding_queue | binding_key |
|-------------------------------------------------------|
| user.write | topic | user.write.app1 | user.* |
| user.write | topic | user.created.app2 | user.created |
Soluzione 4
Il tipo di cambio “argomento” è più flessibile in caso potenzialmente ci saranno più sotto-tipi di eventi. Ma se si conosce chiaramente il numero esatto di eventi, è possibile utilizzare anche il tipo di scambio "diretto" per ottenere prestazioni migliori.
| queue | subscriber |
|---------------------------------|
| user.write.app1 | app1 |
| user.created.app2 | app2 |
| exchange | type | binding_queue | binding_key |
|--------------------------------------------------------|
| user.write | direct | user.write.app1 | user.created |
| user.write | direct | user.write.app1 | user.updated |
| user.write | direct | user.write.app1 | user.deleted |
| user.write | direct | user.created.app2 | user.created |
Torna alla domanda "uno scambio o molti?". Finora, tutte le soluzioni utilizzano solo uno scambio. Funziona bene, niente di sbagliato. Quindi, quando potremmo aver bisogno di più scambi? C'è un leggero calo di prestazioni se uno scambio "argomento" ha troppe associazioni. Se la differenza di prestazioni di troppi legami sullo "scambio di argomenti" diventa davvero un problema, ovviamente è possibile utilizzare più scambi "diretti" per ridurre il numero di associazioni di scambio "argomento" per prestazioni migliori. Ma qui voglio concentrarmi maggiormente sui limiti di funzione delle soluzioni "one exchange".
Soluzione 5
Un caso potremmo considerare natually scambi multipli è per i diversi gruppi o dimensioni di eventi. Ad esempio, oltre agli eventi creati, aggiornati e cancellati già citati sopra, se abbiamo un altro gruppo di eventi: login e logout - un gruppo di eventi che descrivono "comportamenti dell'utente" piuttosto che "scrittura dati". Coz diversi gruppi di eventi potrebbero aver bisogno di strategie di routing completamente diverse e di chiavi di instradamento convenzioni di denominazione delle code &, è così che nativo avere uno scambio separato di user.behavior.
| queue | subscriber |
|----------------------------------|
| user.write.app1 | app1 |
| user.created.app2 | app2 |
| user.behavior.app3 | app3 |
| exchange | type | binding_queue | binding_key |
|--------------------------------------------------------------|
| user.write | topic | user.write.app1 | user.* |
| user.write | topic | user.created.app2 | user.created |
| user.behavior | topic | user.behavior.app3 | user.* |
Altre soluzioni
Ci sono altri casi in cui potremmo aver bisogno scambi multipli per un tipo di oggetto. Ad esempio, se desideri impostare autorizzazioni diverse per gli scambi (ad esempio, solo gli eventi selezionati di un tipo di oggetto possono essere pubblicati in uno scambio da app esterne, mentre l'altro scambio accetta qualsiasi evento dalle app interne). Per un'altra istanza, se si desidera utilizzare diverse piattaforme con suffisso con un numero di versione per supportare versioni diverse delle strategie di routing dello stesso gruppo di eventi. Per un'altra istanza, è possibile definire alcuni "scambi interni" per i collegamenti di scambio-scambio, che potrebbero gestire le regole di routing in modo stratificato.
In sintesi, ancora, "la soluzione finale dipende dalle esigenze del sistema", ma con tutti gli esempi di soluzioni sopra, e con le considerazioni sullo sfondo, spero che possa almeno far pensare a una persona nella giusta direzione.
Ho anche creato a blog post, mettendo insieme questo background di problemi, le soluzioni e altre considerazioni correlate.
buoni punti! Guardando indietro alla mia risposta sopra, mi piace il modo in cui ti stai avvicinando ai nomi delle code come un'azione da eseguire o l'intento di cosa dovrebbe accadere ai messaggi in questa coda. –