領域驅動設計框架Axon實踐

背景
2004年,Eric Evans發表了Domain Driven Design(領域驅動設計,DDD)這一著作,並在書中對領域驅動作出了開創性的理論闡述,至今領域驅動設計已問世十幾年。
近幾年來隨着微服務盛行, ES (Event Sourcing)事件溯源和CQRS (Command Query Responsibility Segregation)讀寫分離也成爲了一個越來越流行的概念,使用ES和CQRS好處在此不做贅述,但是也存在頗多弊端,比如事件數量巨大、回溯狀態需要提前預熱、缺少成熟的框架支撐等。在這種情況下,2009年Allard Buijze在JVM平臺開源了Axon Framework用來解決此問題,簡單說來Axon就是集成了DDD、ES和CQRS於一身,落地實現的一套框架方案,併成立了一家公司Axon IQ,專門與Axon產品合作。
愛奇藝號技術團隊,在實施微服務化過程中,應用領取驅動思想,採用Axon框架落地了多個服務,下面是實施過程中的經驗總結。

技術選型

愛奇藝號合同中臺面向用戶提供簽約功能,從發起簽約到運營審覈、供應商、採購單、掃描件、歸檔等流程漫長,狀態頗多,業務較爲複雜,同第三方系統交互較多,對於有問題數據需要進行定位和回溯。項目初期爲了更好的滿足這些需求,我們調研了一下比較成熟的框架,包括Cola、Axon、Activiti、Spring StateMachine等,圖1-1是框架的一些對比:

圖1-1

從對比中可以看出,Axon支持事件回溯,排查歷史問題較爲方便,並且官方文檔完善,一直處於更新維護中。StateMachine較爲輕量,流程變更對於歷史數據兼容性良好。綜合考慮採用Axon+StateMachine相結合,實現簡版工作流引擎。

Axon框架介紹

Axon框架的程序遵循基於領域驅動設計(DDD)、命令查詢責任隔離 (CQRS)、事件驅動架構(Event Driven Architecture,EDA)的體系結構模式,這些原則的結合,使基於Axon的程序更加健壯、適應性更強。圖1- 2是基於Axon框架程序的典型體系結構:

圖1-2

基於Axon框架程序的典型體系結構圖特性如下:

  1. 領域驅動模型:可以使業務實體不會“貧血”,更加飽滿,實現高內聚、低耦合;
  2. 命令查詢責任隔離:命令模型和查詢模型的分離,使得每個模型更容易理解,更易開發維護,天然適合高併發場景;
  3. 事件驅動架構:支持事件溯源,方便對歷史事件重放,記錄數據變化完整過程,便於BI分析、線上問題排查、還原系統狀態到任意時間點等。

Axon系統調用鏈如圖1-3所示:

圖1-3

Spring StateMachine介紹

Spring StateMachine是使用 Spring框架下的狀態機概念創建的一種應用程序開發框架。它使得狀態機結構層次化,簡化了配置狀態機的過程。擁有有現狀態機的特性功能:現態、條件、動作、次態,支持觸發器、狀態轉移器、保護機制、狀態轉移動作和狀態事件監聽器,可基於Zookeeper實現分佈式狀態機,可配置多層次、結構複雜的狀態機。圖1-4是簡單配置效果圖:

圖1-4

愛奇藝號合同中臺服務實踐

【項目介紹】

用戶入駐愛奇藝號後發表作品會獲得分成收益,賬號滿足一定條件後可以申請提現,提現之前需要跟公司簽約電子合同。爲了保證合同安全有效,線上簽約流程比較漫長,包括用戶填寫信息、運營審覈、採購單申請審覈、合同審覈、合同附件蓋章郵寄、作品關聯等等,累計20+狀態,業務邏輯較爲複雜,需求迭代變更頻繁,對數據一致性要求較高。

項目1.0版本採用的是Activiti工作流作爲引擎設計實現的,基於Activiti特性,可以嚴格控制每一步狀態的流轉,歷史操作事件都會記錄到系統數據庫中,對於線上問題排查有一定的優勢。但是學習成本較大,需要開發人員瞭解框架系統的二十多張表功能、使用BMPN進行流程定義設計等。圖1-5是最初版本的流程設計圖:

圖1-5

隨着業務的發展,想要修改流程設計,增加一些新狀態,此時Activiti的弊端更加暴露出來:如果在原有流程上修改,對於歷史數據的顯示會報錯,如果新增流程,對於正在流程中的數據又沒法使用新流程,只能終止掉重新發起。Activiti針對這種流程升級,或者中國特色式的工作流一直沒有很好的解決辦法,網上的一些解決方法較爲複雜,涉及到修改系統內置數據庫,實現起來成本較大。針對這種情況,愛奇藝號開發團隊對系統進行了升級,採用Axon+Spring StateMachine相結合進行項目架構設計,實現了合同系統2.0版本,最終呈現的結果如圖1-6:

圖1-6

架構說明如下:

  1. 用戶接口層:主要是MQ消息、UI和API接口,接收用戶請求、運營審批命令、第三方系統交互通知等;
  2. 應用層:接口參數校驗、組裝業務參數,轉換成Axon Command進行命令分發;
  3. 領域層:接收到領域事件,轉換成狀態機Event,驅動狀態機進行狀態更迭,觸發對應業務邏輯處理;
  4. 基礎服務層:提供底層存儲服務,第三方服務等。

系統調用流程如下圖1-7:

圖1-7

Axon+StateMachine結合,實現簡版工作流引擎功能,相比於Activiti更加輕量級。以合同對象多爲領域對象,系統操作命令使用狀態機進行控制流轉。所有對系統的修改操作均以Axon的Command進行,Axon會記錄所有對領域對象操作過的事件,可以還原合同生命週期內每一步的狀態,對於問題排查,統計分析有着很大的幫助;snapshot機制對事件進行預熱,解決事件過多加載慢的問題;sage對系統失敗操作進行補償事件,保證系統間數據狀態的一致性;StateMachine特性,可以修改狀態之間流轉走向及流轉條件,新增狀態對於歷史數據或者進行中的數據沒有影響,對系統的迭代開發有很大的效率提升,天然適合互聯網性質工作流。

價值

通過在愛奇藝號後端服務應用Axon框架,可以達成以下效果:

1、 開發方面的優勢

  • 轉換思維:Java語言開發一直提倡面向對象開發,但是很多業務開發人員的思維還是面向過程開發的思維,按照MVC分層進行業務代碼的堆疊。Axon思維更傾向於面向對象,以領域對象爲核心,由於領域對象有明確的領域邊界,所以容易促進開發人員思維模式的轉變。
  • 提升開發效率:項目基於命令模型開發,可以讓熟悉業務的開發人員專注於領域層開發,接口和應用層開發則可以由對業務比較陌生的開發人員負責,二者通過命令發送消息機制進行通信。這種職責分離的優勢在於不需要所有的開發人員都對業務非常熟悉,減少了熟悉具體業務的時間,且每個開發人員都職責明確,可顯著提升開發效率。

2、 運行維護時的優勢

  • 便於問題排查:事件溯源機制使得領域對象的每次操作變更狀態都有記錄,對於排查線上問題有很大的幫助,可以按照先後順序還原對象的每一步狀態。snapshot機制有很好的解決了ES事件預熱的問題。對於BI的分析也有着更好的支撐。
  • 支持系統高吞吐量:CQRS的支持,天然適合高併發場景,如果系統有高併發的需求,使用Axon框架可以得到更好的支持。
  • 便於維護和拓展:Axon框架的代碼層次清晰,易維護,使用的事件機制讓系統更具可擴展性。

難點

  • 分佈式事務一致性問題,saga雖然能保證分佈式事務的最終一致性,但是實施起來困難很大,需要開發各種補償機制來實現。而且沒有考慮到服務的宕機、冪等、重試支持等問題
  • 批量事務處理能力較弱,對於一些批量功能,目前只能轉換成單獨的命令進行處理,沒有提供很好的批處理能力。
  • 與Spring cloud整合問題,Axon支持與Spring Cloud結合,使用分佈式消息隊列來實現分佈式系統間命令的分發,但是目前沒有比較良好的實現,中文文檔較少,需要進一步研究實施。
  • Axon的充血模型雖然是一大特色,但是實施起來比較繁瑣,對於簡單的業務實現,貧血模型更加適合。
  • 中文文檔少,上手難度較高,國內使用人少,遇到問題可請教或討論的人少。

未來規劃

從4.0版本開始,Axon已經不止是個框架,而是一個由Axon Framework和Axon Server組成的平臺。目前官方發佈的最新Axon版本已經是v4.3.3,本文中的項目基於Axon框架v3.04進行開發,並且是基於單機事件傳播,對於Axon Server機制還未深入研究使用。另外對於一些高級特性如:與Spring Cloud整合、分佈式命令、分佈式事件、分佈式事務等需要進一步實踐和總結。Axon命令分發支持與配置AMQP協議的MQ(Message Queue)綁定,MQ用於把Event分發到MQ中,採用這種機制可以針對性的對服務進行更細粒度的拆分,命令分發和處理可以配置成不同的模塊,按照各自吞吐量進行服務部署。此外,分佈式事務一直是個令人頭疼的問題,對於saga的優雅實現需要花費更多的時間進行深入研究。

領域思想的轉變對面向對象開發語言有着重大的幫助,成熟的架構支持及持久的維護性對於技術選型有着很大的影響,流行的Axon, Akka, Cola等框架勢頭正猛,相信領域思想未來會更深入人心。

作者介紹

本文轉載自公衆號愛奇藝技術產品團隊(ID:iQIYI-TP)。

原文鏈接

領域驅動設計框架Axon實踐

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章