32 | 集成事件:解決跨微服務的最終一致性
首先看一下集成事件的工作原理
它的目的時為了實現系統的集成,它主要是用於系統里面多個微服務之間相互傳遞事件
集成事件的實現方式有兩種,一種是圖上顯示的發布訂閱的方式,通過 EventBus,還有一種方式是通過觀察者模式,由觀察者將事件發送給關注事件的人
接着看一下代碼上的定義
在 Application 目錄下面定義了一個集成事件的目錄 IntegrationEvents
OrderCreatedIntegrationEvent
namespace GeekTime.API.Application.IntegrationEvents
{
public class OrderCreatedIntegrationEvent
{
public OrderCreatedIntegrationEvent(long orderId) => OrderId = orderId;
public long OrderId { get; }
}
}
得益於基礎設施的發展,現在實際上可以借助一些開源框架,很輕松的實現集成事件的發布和訂閱的能力
在發布端可以看一下這里的代碼
namespace GeekTime.API.Application.DomainEventHandlers
{
public class OrderCreatedDomainEventHandler : IDomainEventHandler<OrderCreatedDomainEvent>
{
ICapPublisher _capPublisher;
public OrderCreatedDomainEventHandler(ICapPublisher capPublisher)
{
_capPublisher = capPublisher;
}
public async Task Handle(OrderCreatedDomainEvent notification, CancellationToken cancellationToken)
{
await _capPublisher.PublishAsync("OrderCreated", new OrderCreatedIntegrationEvent(notification.Order.Id));
}
}
}
這里我們定義了一個領域事件,它的作用就是將我們的集成事件發送出去,具體是要發送到 RabbitMQ 還是 kafka 這些消息隊列中間件里面是可配置的,對於業務邏輯來講的話,它是透明的
這里有一個 ICapPublisher 接口,這個接口實際上是由中國的開源社區開發的一個框架,借助這個框架,我們可以輕松的實現消息的發布和訂閱
那我們如何來訂閱其他微服務發出的消息呢?
namespace GeekTime.API.Application.IntegrationEvents
{
public class SubscriberService : ISubscriberService, ICapSubscribe
{
IMediator _mediator;
public SubscriberService(IMediator mediator)
{
_mediator = mediator;
}
[CapSubscribe("OrderPaymentSucceeded")]
public void OrderPaymentSucceeded(OrderPaymentSucceededIntegrationEvent @event)
{
//Do SomeThing
}
[CapSubscribe("OrderCreated")]
public void OrderCreated(OrderCreatedIntegrationEvent @event)
{
//Do SomeThing
}
}
}
我們可以通過訂閱服務,它同樣也是借助了 Cap 的組件,我們實現了 ICapPublisher 這個接口,就可以將服務標記成我們的訂閱服務
另外我們的訂閱方法,訂閱的處理函數上面,標記 CapSubscribe 這個屬性,將我們要訂閱的事件名放在這里,我們就可以訂閱到這個事件了
namespace GeekTime.API.Application.IntegrationEvents
{
public class OrderPaymentSucceededIntegrationEvent
{
public OrderPaymentSucceededIntegrationEvent(long orderId) => OrderId = orderId;
public long OrderId { get; }
}
}
我們可以看到集成事件定義的話,它是沒有接口和基類的約束的,因為在異構的系統里面,對於集成事件來講的定義是相對比較靈活的,我們的建議是用這種簡單的類型來承載它即可
總結一下
集成事件實際上也是由領域的業務邏輯驅動的,它本質上也是領域事件,只是說它是跨服務的領域事件
另外一個集成事件大部分場景是領域事件驅動的,也有可能是一些比如說定時任務觸發的,由於集成事件是跨微服務來傳遞信息的,所以我們沒辦法通過事務來處理,那就需要借助 Cap 這樣的框架來實現最終的一致性
當然我們建議僅在必要的情況下定義和使用集成事件,因為一旦引入集成事件,比如 EventBus,我們應用程序的版本控制,比如說我們發布新版本的時候,新舊版本的事件的發布和訂閱都會受到影響,這個時候我們沒辦法使我們的應用程序成為一個單純的無狀態的程序,在更新新版本的時候,那么就會帶來新的負擔,兼容性方面我們會需要做更多的工作
GitHub源碼鏈接:
https://github.com/witskeeper/geektime
本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。
歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含鏈接: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改后的作品務必以相同的許可發布。
如有任何疑問,請與我聯系 (MingsonZheng@outlook.com) 。