Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Suggerimento
Questo contenuto è un estratto dell'eBook, Architettura di microservizi .NET per applicazioni .NET containerizzati, disponibile in documentazione .NET o come PDF scaricabile gratuitamente leggibile offline.
Come descritto in precedenza, quando si usa la comunicazione basata su eventi, un microservizio pubblica un evento quando si verifica un evento rilevante, ad esempio quando aggiorna un'entità business. Altri microservizi sottoscrivono tali eventi. Quando un microservizio riceve un evento, può aggiornare le proprie entità aziendali, che potrebbero causare la pubblicazione di più eventi. Questa è l'essenza del concetto di coerenza finale. Questo sistema di pubblicazione/sottoscrizione viene in genere eseguito usando un'implementazione di un bus di eventi. Il bus di eventi può essere progettato come interfaccia con l'API necessaria per sottoscrivere e annullare la sottoscrizione agli eventi e pubblicare eventi. Può anche avere una o più implementazioni basate su qualsiasi comunicazione tra processi o messaggi, ad esempio una coda di messaggistica o un bus di servizio che supporta la comunicazione asincrona e un modello di pubblicazione/sottoscrizione.
È possibile usare gli eventi per implementare transazioni aziendali che si estendono su più servizi, che offrono la coerenza finale tra tali servizi. Una transazione coerente finale è costituita da una serie di azioni distribuite. A ogni azione, il microservizio aggiorna un'entità business e pubblica un evento che attiva l'azione successiva. Tenere presente che la transazione non copre la persistenza sottostante e il bus di eventi, quindi l'idempotenza deve essere gestita. La figura 6-18 seguente mostra un evento PriceUpdated pubblicato tramite un bus di eventi, quindi l'aggiornamento del prezzo viene propagato al basket e ad altri microservizi.
Figura 6-18. Comunicazione guidata da eventi basata su un bus di eventi
Questa sezione descrive come implementare questo tipo di comunicazione con .NET usando un'interfaccia generica del bus di eventi, come illustrato nella figura 6-18. Esistono più implementazioni potenziali, ognuna con una tecnologia o un'infrastruttura diversa, ad esempio RabbitMQ, il bus di servizio di Azure o qualsiasi altro bus di servizio open source o commerciale di terze parti.
Uso di broker di messaggi e bus di servizio per i sistemi di produzione
Come indicato nella sezione architettura, è possibile scegliere tra più tecnologie di messaggistica per implementare il bus di eventi astratto. Ma queste tecnologie sono a livelli diversi. Ad esempio, RabbitMQ, un broker di trasporto di messaggi, è a un livello inferiore rispetto ai prodotti commerciali come Azure Service Bus, NServiceBus, MassTransit o Brighter. La maggior parte di questi prodotti può funzionare su RabbitMQ o sul bus di servizio di Azure. La scelta del prodotto dipende dal numero di funzionalità e dalla scalabilità predefinita necessaria per l'applicazione.
Per implementare solo una prova di concetto di un bus di eventi per l'ambiente di sviluppo, come nell'esempio eShopOnContainers, una semplice implementazione di RabbitMQ in esecuzione come container potrebbe essere sufficiente. Tuttavia, per i sistemi cruciali e di produzione che richiedono una scalabilità elevata, è consigliabile valutare e usare il bus di servizio di Azure.
Se sono necessarie astrazioni di alto livello e funzionalità più avanzate come Sagas per processi a esecuzione prolungata che semplificano lo sviluppo distribuito, altri bus di servizio commerciali e open source come NServiceBus, MassTransit e Brighter valgono la pena valutare. In questo caso, le astrazioni e l'API da usare sono in genere direttamente quelle fornite da tali bus di servizio di alto livello invece delle proprie astrazioni (come le astrazioni semplici del bus di eventi fornite in eShopOnContainers). In questo caso, è possibile ricercare l'eShopOnContainers forked usando NServiceBus (esempio derivato aggiuntivo implementato da Particular Software).
Naturalmente, è sempre possibile creare funzionalità del bus di servizio personalizzate su tecnologie di livello inferiore come RabbitMQ e Docker, ma il lavoro necessario per "reinventare la ruota" potrebbe essere troppo costoso per un'applicazione aziendale personalizzata.
Per ribadire: le astrazioni e l'implementazione del bus di eventi di esempio presentate nell'esempio eShopOnContainers devono essere usate solo come modello di verifica. Dopo aver deciso di avere una comunicazione asincrona e guidata dagli eventi, come illustrato nella sezione corrente, è consigliabile scegliere il prodotto del bus di servizio più adatto alle esigenze di produzione.
Eventi di integrazione
Gli eventi di integrazione vengono usati per sincronizzare lo stato del dominio tra più microservizi o sistemi esterni. Questa funzionalità viene eseguita pubblicando eventi di integrazione all'esterno del microservizio. Quando un evento viene pubblicato in più microservizi ricevitori (a tutti i microservizi sottoscritti all'evento di integrazione), il gestore eventi appropriato in ogni microservizio ricevitore gestisce l'evento.
Un evento di integrazione è fondamentalmente una classe di controllo dei dati, come nell'esempio seguente:
public class ProductPriceChangedIntegrationEvent : IntegrationEvent
{
public int ProductId { get; private set; }
public decimal NewPrice { get; private set; }
public decimal OldPrice { get; private set; }
public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice,
decimal oldPrice)
{
ProductId = productId;
NewPrice = newPrice;
OldPrice = oldPrice;
}
}
Gli eventi di integrazione possono essere definiti a livello di applicazione di ogni microservizio, in modo che vengano separati da altri microservizi, in modo paragonabile al modo in cui i ViewModel vengono definiti nel server e nel client. Cosa non è consigliabile è condividere una libreria di eventi di integrazione comune tra più microservizi; in questo modo questi microservizi verranno accoppiati con una singola libreria di dati di definizione dell'evento. Non si vuole farlo per gli stessi motivi per cui non si vuole condividere un modello di dominio comune tra più microservizi: i microservizi devono essere completamente autonomi. Per altre informazioni, vedere questo post di blog sulla quantità di dati da inserire negli eventi. Fare attenzione a non spingersi troppo oltre, poiché questo altro post del blog descrive il problema che i messaggi carenti di dati possono causare. La progettazione degli eventi deve essere "giusta" per le esigenze dei propri consumatori.
Esistono solo alcuni tipi di librerie da condividere tra microservizi. Una è costituito da librerie che sono blocchi di applicazioni finali, come l'API client del bus di eventi, come in eShopOnContainers. Un'altra è costituita da librerie che costituiscono strumenti che possono essere condivisi anche come componenti NuGet, ad esempio serializzatori JSON.
Bus di eventi
Un bus di eventi consente la comunicazione in stile di pubblicazione/sottoscrizione tra microservizi senza che i componenti siano a conoscenza esplicitamente degli uni degli altri, come illustrato nella figura 6-19.
Figura 6-19. Elementi fondamentali di pubblicazione/sottoscrizione con un event bus
Il diagramma precedente mostra che il microservizio A pubblica sul bus di eventi, che distribuisce ai microservizi B e C abbonati, senza che il pubblicatore debba conoscere i sottoscrittori. Il bus di eventi è correlato al modello Observer e al modello publish-subscribe.
Modello observer
Nel modello Observer l'oggetto primario (noto come Observable) invia una notifica ad altri oggetti interessati (noti come Osservatori) con informazioni rilevanti (eventi).
Modello Publish/Subscribe (Pub/Sub)
Lo scopo del modello Publish/Subscribe è lo stesso del modello Observer: si vuole inviare una notifica ad altri servizi quando si svolgono determinati eventi. Ma c'è una differenza importante tra gli schemi Observer e Pub/Sub. Nel modello osservatore, la trasmissione viene eseguita direttamente dall'osservabile agli osservatori, quindi si "conoscono" l'uno dall'altro. Tuttavia, quando si usa un modello Pub/Sub, è presente un terzo componente, denominato broker o broker di messaggi o bus di eventi, noto sia dal server di pubblicazione che dal sottoscrittore. Pertanto, quando si usa il modello Pub/Sub, l'editore e i sottoscrittori sono esattamente disaccoppiati grazie al bus di eventi o al broker di messaggi menzionato.
Il middleman o il bus di eventi
Come si ottiene l'anonimato tra editore e sottoscrittore? Un modo semplice è lasciare che un intermediario si occupi di tutte le comunicazioni. Un event bus è uno di questi intermediari.
Un bus di eventi è in genere composto da due parti:
L'astrazione o l'interfaccia.
Una o più implementazioni.
Nella figura 6-19 è possibile vedere come, dal punto di vista dell'applicazione, il bus di eventi non è altro che un canale Pub/Sub. Il modo in cui si implementa questa comunicazione asincrona può variare. Può avere più implementazioni in modo che sia possibile scambiarle, a seconda dei requisiti dell'ambiente ( ad esempio, produzione e ambienti di sviluppo).
Nella figura 6-20 è possibile visualizzare un'astrazione di un bus di eventi con più implementazioni basate su tecnologie di messaggistica dell'infrastruttura come RabbitMQ, bus di servizio di Azure o un altro broker di eventi/messaggi.
Figura 6- 20. Implementazioni multiple di un bus di eventi
È consigliabile definire il bus di eventi tramite un'interfaccia in modo che possa essere implementato con diverse tecnologie, ad esempio RabbitMQ, bus di servizio di Azure o altri. Tuttavia, e come accennato in precedenza, l'uso delle proprie astrazioni (l'interfaccia del bus di eventi) è valido solo se sono necessarie funzionalità di base del bus di eventi supportate dalle astrazioni. Se sono necessarie funzionalità più avanzate del bus di servizio, è consigliabile usare l'API e le astrazioni fornite dal bus di servizio commerciale preferito anziché le astrazioni personalizzate.
Definizione di un'interfaccia del bus di eventi
Si inizierà con un codice di implementazione per l'interfaccia del bus di eventi e le possibili implementazioni a scopo di esplorazione. L'interfaccia deve essere generica e semplice, come nell'interfaccia seguente.
public interface IEventBus
{
void Publish(IntegrationEvent @event);
void Subscribe<T, TH>()
where T : IntegrationEvent
where TH : IIntegrationEventHandler<T>;
void SubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void UnsubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void Unsubscribe<T, TH>()
where TH : IIntegrationEventHandler<T>
where T : IntegrationEvent;
}
Il Publish
metodo è semplice. Il bus di eventi trasmetterà l'evento di integrazione passato a qualsiasi microservizio o anche a un'applicazione esterna, sottoscritta a tale evento. Questo metodo viene utilizzato dal microservizio che pubblica l'evento.
I Subscribe
metodi (è possibile avere diverse implementazioni a seconda degli argomenti) vengono usati dai microservizi che vogliono ricevere eventi. Questo metodo ha due argomenti. Il primo è l'evento di integrazione a cui sottoscrivere (IntegrationEvent
). Il secondo argomento è il gestore dell'evento di integrazione (o il metodo di callback), denominato IIntegrationEventHandler<T>
, da eseguire quando il microservizio ricevitore ottiene tale messaggio di evento di integrazione.
Risorse aggiuntive
Alcune soluzioni di messaggistica pronte per la produzione:
Bus di servizio di Azure
https://learn.microsoft.com/azure/service-bus-messaging/NServiceBus
https://particular.net/nservicebusMassTransit
https://masstransit-project.com/