在開發(fā)微服務(wù)的過程中妄均,分布式數(shù)據(jù)管理是必須解決的問題。不同服務(wù)數(shù)據(jù)庫選擇的多樣性哪自,事務(wù)問題及跨服務(wù)的數(shù)據(jù)查詢都是我們要面對的挑戰(zhàn)丰包。
對于大多數(shù)應(yīng)用而言,要實現(xiàn)微服務(wù)和管理分布數(shù)據(jù)壤巷,都需要采用事件驅(qū)動架構(gòu)邑彪。在事件驅(qū)動架構(gòu)中,某個服務(wù)在發(fā)生重要事情的時候胧华,比如寄症,創(chuàng)建一個訂單會發(fā)布一個事件宙彪,而其他服務(wù)訂閱這些事件。作為對事件的回應(yīng)有巧,接收事件的服務(wù)通常會更新自身的狀態(tài)释漆,或許會發(fā)布更多事件,讓其他服務(wù)進行更新篮迎。
我們分析一下上述用例男图,我的的業(yè)務(wù)代碼必需完成在MySQL數(shù)據(jù)庫中加入訂單相關(guān)數(shù)據(jù)并將事件發(fā)布到Kafka中。如何避免不一致性發(fā)生甜橱,保證這兩個操作在同一個事務(wù)中呢享言?
傳統(tǒng)方法中,我們可以使用包含數(shù)據(jù)庫和消息代理的分布式事務(wù)渗鬼,但我們都知道分布式事務(wù)帶來的諸多問題與限制,荧琼。然而譬胎,事件溯源(Event Sourcing)也是一個不錯的辦法。它已經(jīng)存在了幾十年命锄,直到Greg Young用于DDD中后堰乔,逐步流行了起來。
這里我們借助Martin Fowler對事件溯源給出的一些解釋:
事件溯源的核心理念是說脐恩,在對系統(tǒng)的狀態(tài)做出變更時镐侯,把每次變更記錄為一個事件,在未來的任何時刻驶冒,都可以通過重新處理這些事件來重建系統(tǒng)的狀態(tài)苟翻。事件存儲是主要的事件來源,可以從事件存儲中重建系統(tǒng)的狀態(tài)骗污。對于程序員來說崇猫,版本控制系統(tǒng)是一個最好的例子。提交日志就是事件存儲需忿,而代碼工作副本就是系統(tǒng)狀態(tài)诅炉。在某個指定的工作副本上重播提交日志就可以創(chuàng)建另一個工作副本,也就是重建了某個時刻的系統(tǒng)狀態(tài)屋厘。
拿訂單為例涕烧,在整個訂單的生命周期中所發(fā)生的重要的事情,都會記錄在事件存儲中汗洒。
再看看事件事件溯源是如何工作的:
這里的訂單是訂單服務(wù)中的訂單聚合议纯,可能有的讀者會問,這樣的架構(gòu)怎樣解決訂單更新與保存的一致性呢仲翎?其實訂單沒有對應(yīng)的MySQL數(shù)據(jù)庫痹扇,只存在于內(nèi)存中铛漓,需要持久化的只有訂單業(yè)務(wù)過程中的領(lǐng)域事件,保存在了事件存儲中鲫构,單一的存儲類型浓恶,這樣就不存在一致性問題了。
關(guān)于不同服務(wù)的joins問題结笨,事件溯源推薦使用CQRS架構(gòu)包晰,將查詢與事件處理分離,在DDD中我們會定義成領(lǐng)域報告炕吸。詳細內(nèi)容后續(xù)文章會有處理伐憾。