eShopOnContainers 知(zhi)多少[4]:Catalog microservice
引言
Catalog microservice(目錄微服務(wu)(wu))維(wei)護著所有(you)產品信息(xi),包括庫存、價(jia)格(ge)。所以該微服務(wu)(wu)的核心(xin)業(ye)務(wu)(wu)為:
- 產品信息的維護
- 庫存的更新
- 價格的維護
架構模式

如上圖所示,本微服務采用簡單的數據驅動的CRUD微服務架構,來執行產品信息的創建、讀取、更新和刪除(CRUD)操作。
這種類型的服務在單個 ASP.NET Core Web API 項目中即可實現所有功能,該項目包括數據模型類、業務邏輯類及其數據訪問類。其項目結構如下:

核心技術選型:
- ASP.NET Core Web API
- Entity Framework Core
- SQL Server
- Swashbuckle(可選)
- Autofac
- Eventbus
- Polly
實體建模
該微服務的核心領域實體是商品,其類圖如下:
對于(yu)實體(ti)這一塊(kuai),有兩個小(xiao)知識點需要說明一下:
- 進行數據庫字段映射時,主鍵都使用了
ForSqlServerUseSequenceHiLo指定使用HI-LO高低位序列進行主鍵生成。 - 使用NoTracking提升查詢速度
在CatalogController的構造方法中,明確指定以下代碼來進行查詢優化,這一點也是我們值得學習的地方。((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - 在進行種子數據的預置時,使用了
Polly開啟了Retry機制。
private Policy CreatePolicy( ILogger<CatalogContextSeed> logger, string prefix,int retries = 3)
{
return Policy.Handle<SqlException>().
WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
onRetry: (exception, timeSpan, retry, ctx) =>
{
logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
}
);
}
public async Task SeedAsync(CatalogContext context,IHostingEnvironment env,IOptions<CatalogSettings> settings,ILogger<CatalogContextSeed> logger)
{
var policy = CreatePolicy(logger, nameof(CatalogContextSeed));
await policy.ExecuteAsync(async () =>
{
//...
});
}
數據庫表結構

你肯定會好奇為什么會多了一張IntegrationEventLog表,這里先按住不(bu)表。
最后
如(ru)果eShopOnContainers采用的(de)是單體(ti)式(shi)應用架(jia)構(gou)而(er)非微(wei)服務架(jia)構(gou),那(nei)么以上(shang)業務邏(luo)輯的(de)實現并不復(fu)雜(za),使用簡(jian)單的(de)CRUD再輔以ACID事(shi)務就能很好的(de)完成業務需(xu)求。本文(wen)的(de)介紹也就可以到此為(wei)止(zhi)了。
然而將其(qi)抽取出(chu)來(lai)成為獨立的基礎微(wei)服務(wu),那么我們要考慮的問(wen)題(ti)就多(duo)了(le)。比如:
- 修改產品價格時,需要同步更新購物車中保存的產品信息的價格。
- 下訂單時,需要驗證當前商品庫存是否充足,進行鎖庫搶占,以避免庫存不足導致的訂單無效。
而這一(yi)切我們都(dou)不(bu)能再(zai)享受單體應用(yong)中(zhong)直(zhi)接(jie)使(shi)用(yong)ACID事(shi)務(wu)的(de)便利(li)了。因(yin)為在(zai)微(wei)服務(wu)應用(yong)里,產(chan)品(pin)(pin)表和(he)購物籃(lan)(lan)表被各自的(de)微(wei)服務(wu)所(suo)占有。任何(he)微(wei)服務(wu)不(bu)應該在(zai)自己的(de)事(shi)務(wu)中(zhong)包(bao)含其他微(wei)服務(wu)的(de)表或存儲(chu),即使(shi)是直(zhi)接(jie)查詢也是不(bu)可以的(de)。目(mu)錄微(wei)服務(wu)不(bu)能直(zhi)接(jie)更新購物籃(lan)(lan)表,因(yin)為購物籃(lan)(lan)表被購物籃(lan)(lan)微(wei)服務(wu)占有。要更新購物籃(lan)(lan)微(wei)服務(wu),產(chan)品(pin)(pin)微(wei)服務(wu)應該使(shi)用(yong)基于(yu)異(yi)步通信,如集成事(shi)件(消息和(he)基于(yu)事(shi)件的(de)通信)來(lai)實現最(zui)終一(yi)致性(xing)。
那下一節(jie)我們就(jiu)來詳細(xi)闡述eShopOnContainers是如何通過事件機制完(wan)成最終一致性的。
??面向.NET開發者的AI Agent 開發課程【.NET+AI | 智能體開發進階】已上線,歡迎掃碼加入學習。??
關注我的公眾號『向 AI 而行』,我們微信不見不散。
閱罷此文,如果您覺得本文不錯并有所收獲,請【打賞】或【推薦】,也可【評論】留下您的問題或建議與我交流。 你的支持是我不斷創作和分享的不竭動力!
