一. 背景
- 應用系統的架構演變隨着業務的越來越復雜,需要更多的思考、更高維度的抽象。
- 將組織邏輯與業務實現分離,使業務應用更關注自身的領域內容。
二. 目標
將業務流程可視化、最終展現出全局業務視圖,並可以動態調整業務鏈路。結尾附上示例代碼。
大部分現行的系統都是通過繁榮的代碼來實現業務邏輯的拼裝,當業務變得極其復雜的時候會變得可讀性極差,可維護性降低。
服務編排的理想目標是開發人員只注重簡單接口(行為)的開發,業務人員可以通過編排系統實現應用及系統的組裝和運維。簡單一點理解的話就是講服務化衍進為工具化(理想狀態,現實很難)。
三. 產出
- 一個中心化的流程配置站點,效果如圖(引用zeebe的系統圖)
- 一個輕量級的編排網關,使用網關模式(中心化)、業務接口將不直接暴露服務,所有請求由網關組織,類似總線模式。優點在於對於新的應用,開發者只需關注自己的原子功能實現,缺點在於對於舊的應用,部分業務接口需要拆解改造。
- 一個客戶端代理,使用代理模式(非中心化)、中心化的配置站點根據版本下發規則文件,需要在各自應用系統中引用代理組件,可以自動/按需進行服務組織調用與上下文適配。
ps:對於網關模式和代理模式一般只需要采取1種,具體根據自己的實際場景選擇。
四. 與工作流區別
- 從實現方向上來說,工作流引擎的核心實現是一種狀態機、可以理解成一套中心化的服務;服務編排的核心是一套開發框架,它依賴接入應用的具體場景。
- 從業務方向來說,工作流引擎側重構建定義執行過程,強調規范、快速開發;服務編排側重業務建模、組裝、部署及管理。
- 從使用場景來說,工作流引擎一室現在最大的使用場景為辦公自動化;服務編排可以理解成SOA的產物。
五. 應用場景分析
簡單的來說,這種場景對應網關模式,無需代碼侵入,由編排網關統籌管理服務調度,粒度可以足夠的細,一次db操作,一次文件操作,一次接口調用都可以作為調度的基本單元。端點的概念在后面實現里會講。
這種場景為代理模式,需要少量的代碼侵入,侵入部分為編排的組件代理,這種模式可以解決中心化的問題,各自應用自己治理。
宏觀的概念為企業應用模式,通過編排引擎將應用系統、數據資源和互聯網資源組成一個統一的整體。看起來是不是和ESB有點像,很快我們會總結和ESB的差異。
核心模塊參考Netflix conductor 、Zeebe、Apache Camel等成熟產品 結合我們自己業務特性,目標為輕量級、可擴展、組件化的設計模式。
黃色的部分就是服務編排組件和ESB產品重疊的內容,服務編排組件相當於是ESB產品成熟架構之上的一些功能拆解,並逐漸衍生為更貼合互聯網主流技術(例如微服務)的替代方案。
上面我們聊了2種模式,我們通過管道與業務域的關系來解釋部署方案的差異
管道是消息傳遞的載體。由於編排引擎的核心為組件化的實現方式,其部署的方式相對靈活。
1. 管道的范圍決定了業務域的大小 高緯度能以整個團隊業務為維度,低緯度能以個別應用為維度。
2. 中心化部署 好處是可以避免下層應用代碼的侵入並集中管理
3.非中心化部署 非中心化部署有2種方式
i)第一種為代碼植入,這種方式不依賴管道作為消息載體,每一個植入應用都屬於消息載體,並直接管理上下文。
ii)第二種為ServiceMesh的邊車模式,將控制與業務分離。好處是無需進行代碼侵入,缺點是當前環境該模式並不成熟,容易帶入運維成本。
除了路由可視化,還可以利用JMX實現擴展管理,Mbean中包含了所有可更新對象。 消息管道中按每筆事件定義通信ID,通信ID在一次傳遞過程中不會變化,其中包含版本信息。 新版本的產生不會影響到舊的事件。
六. 核心組件實現
重點參考開源產品Apache Camel。最核心的是DSL語言、端點、組件、路由、注冊表、格式轉化。
DSL 其實是 Domain Specific Language 的縮寫,相對DSL的定義就是 GPL(General Purpose Language)
常見的DSL有SQL、Regex ,常見的GPL有Objective-C、Python...
DSL 最大的設計原則就是簡單,通過簡化語言中的元素,降低使用者的負擔設計語法和語義。Camel組件中設計DSL語法和語義,定義 DSL 中的元素並實現 parser,對 DSL 解析,最終通過解釋器來執行。目前支持Java DSL和XML DSL。其核心定義就是描述了一次路由行為的上下文、內容、類型、依賴、邏輯等等。運行時編排系統就會載入實現定義的DSL文件,會按照DSL文件中定義的路由行為來執行。
回到上面提出的問題,什么是端點(Endpoint)。端點是camel的抽象概念。可以理解成信道末端模型,系統可以利用信道收發消息。更通俗一點來講,你可以將端點理解成一次通信行為的支撐/目標支點。這個支點可以支持非常多的協議,例如http、ftp、rpc等等等等。這從基礎上就決定了我們的通信信道不僅僅可以支撐現在常用的服務/微服務場景,更能從更多底層元素來運作編排行為。
但是端點需要滿足一定的規則要求,首先是路由Url,示例中的file代表Scheme,定義了端點的協議類型。Context path定義通信的路徑及端口等。Options定外額外的一些擴展信息,根據協議和場景的特殊性可以自定義邏輯和內容。
端點還關聯着生產者、消費者、交換機等概念,這些內容的設計和實現和RabbitMq同源,RabbitMq的底層設計就是使用了Camel的框架。
關於這些概念可以參與我之前的文章 https://www.cnblogs.com/dubing/p/4017613.html
組件的概念如下圖
組件的實現方式為監控指定目錄中的文件。此目錄中的文件描述了組件的名稱、組件類的全路徑名。 大部分組件的java代碼模塊都與模塊核心模塊做了分離,因為他們常常依賴第三方的包,如果不分離,將會使核心包過度膨脹。
整個端點實現的類圖可以參考下圖
下面我們接着講路由
Multicast表示將消息復制多份串行/並行分開給所有消費通道。
RecipientList區別於多播模式,解決消費通道優先級問題。收件人列表可以動態維護。
routeSliping是將消息依次傳入后面的節點進行處理,不會負責,后面的節點修改的是同一個消息。
此外還有多種傳遞類型,例如SPLIT將一份消息分離成不同部分傳遞給不同消息通道,Aggregator將不同消息來源合並給下游消息通道。
如果組件支持的模式不足以滿足我們項目的特性需求還可以自定義規則
示例中根據choice-when 自定義路由規則。
代碼示例
本章總覽了服務編排的設計,內容較多每一塊的細節都可以單獨拿出來詳細解讀,最后附上組件示例代碼(示例代碼為完全demo環境,如發現任何企業或者版權相關信息請聯系我刪除)