天天看點

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

1. 定義

企業數字化轉型的道路上,必不可少的一項就是審批流程的線上化,都需要搭建自己的審批系統,而審批系統的核心就是審批流引擎

什麼是審批流引擎呢?

是一個工具包,用來驅動審批類業務的執行,通過使用這個引擎,可以友善快速的實作各類審批相關的功能,如:審批、同意、或簽、并簽、串簽、拒絕、駁回、回退到任意節點、前加簽、後加簽、平行加簽、平行減簽、外部調用節點、抄送、填寫、主子流程、分支、選擇、流程預測、流程仿真、取回、撤銷、傳閱、以及各種加減簽與或并簽的任意嵌套。

2. 現有技術

業内的現有技術一般分為三大派系,一個是直接使用開源的工作流引擎作為審批流引擎,一個是在開源的工作流引擎的基礎之上進行的二次開發,最後一個是完全的自研

2.1 開源的工作流引擎

這種技術的一個基本的邏輯就是把工作流引擎當做審批流引擎來使用,常見的就是activiti,也有flowable、camunda,但由于它們二者都是直接或間接來自于actitivi,雖然做了一些改進,但差別不是很大。

以activti為例,一個典型的技術架構如下圖所示:

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

實踐中,使用BPMN2.0協定作為審批流流程定義的載體,使用activiti工作流引擎解析并執行這個流程,引擎通過回調的方式來執行自定義的審批業務,審批業務通過API的方式來調用引擎,如此循環,直到結束。需要注意的是,Client可以調用其中的任何一層

這種技術優缺點如下

優點:

  • 開源的多年成熟技術
  • 文檔資料比較多

缺點:

  • 對絕大部分審批業務沒有直接的API或回調支援,需要自己開發
  • 一些複雜的場景,如:或并簽與加減簽的無限嵌套,支援的力度非常的弱,有時需要繞過工作流引擎,而去直接修改資料庫本身,這樣帶來的危害是比較大的
  • 開源的代碼量巨大,50W行左右,遇到一些棘手的問題,又找不到資料,必需看源碼找問題的時候,會非常非常的痛苦,對開發不友好,學習成本高
  • 與BPMN協定依賴性較強,因審批流協定與BPMN協定的交集較小,需要BPMN協定的擴充功能來表達審批流語義,導緻語義含糊,表達力不強

從根本上來說,直接把工作流引擎當做審批流引擎是混淆了工作流與審批流的概念,把一些審批流的邏輯範疇強行加到工作流上,把個性當共性,最終導緻了複雜性的爆炸,審批業務做的不倫不類,無法做大做強。

2.2 二次開發

這種技術是在開源的工作流引擎的基礎之上進行的二次開發,把activiti之流當做底層的技術底座,進行了一些封裝,一般的技術架構如下圖所示:

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

使用的時候,Client直接調用審批流API接口,然後進行相應的邏輯處理,最後調用工作流引擎,完成整個流程

  • 屏蔽了底層技術細節,接口對使用者友好
  • 對大部分審批業務提供了直接的支援
  • 因其技術底座使用了activiti之流,故其帶來的困擾一點沒有減少,直接對引擎的維護者不友好,間接提高BUG率,進而影響上層業務,不穩定性增大
  • 對一些特定的RDBMS的支援較差,如:達夢國産資料庫、自研的記憶體資料庫,需要做大量的二次開發,修改底層源代碼
  • 對資料庫的異構性支援幾乎沒有,會直接影響本地事務的一緻性

2.3 自研

每一家的解決方案各自不同,使用的技術底座不同,協定不同,持久化機制不同,接口參數不同,但一個相同的邏輯就是有針對性的對審批業務提供了直接的支援,不在混淆工作流與審批流的概念,對開發更加的友好,開發更加的簡單,同時對現有的審批業務的範疇之内,提供了一些擴充能力,雖然有上述優點,缺點也不容易忽視,如下:

  • 如果審批業務有了進化,提出了一些新的概念,而擴充性又覆寫不到的話,那麼就需要開發引擎本身來進行支援,這對于軟體的分發、更新、部署、資料一緻性方面提出了挑戰
  • 與某一持久化機制強綁定,無論是RDBMS、KV還是檔案,顯得很笨重,內建的時候,會引起與現有基礎設施不一緻的問題,很是麻煩

3. 我們的技術

我們采用的是自研的方式,走了一條很不一樣的技術路線,完全自研了工作流引擎架構,在這基礎之上,建構了自己的審批流引擎,具有如下的特點:

  • 與審批業務強耦合,開箱即用
  • 使用簡單,貧血模型,無狀态依賴
  • 本身代碼量少,1W行左右,易于維護
  • 隻是一個jar包,可嵌入到任何業務系統中
  • 不依賴具體的資料庫,無論關系型的還是非關系型的,對持久化提供了擴充
  • 不依賴某一個流程協定,如:BPMN,而是使用類似流程虛拟機的形式,對審批流定義本身提供了支援
  • 可擴充自己業務特定的流程節點
  • 可擴充自己業務特定的執行人指定邏輯
  • 可擴充自己業務特定的流程流轉事件
  • 依賴少,隻依賴slf4j、kryo等必要元件,不依賴任何工作流引擎,如:activiti、flowable等
  • 可以友善的內建進Spring MVC,Spring Boot等
  • 可以友善的控制本地事務、事務內建等
  • 可運作時确定具體審批人,而不是在定義期
  • 擴充性合适,既不是什麼都可以擴充,也不是什麼都不可以擴充,即:隻擴充那些與審批相關的點

下面詳細闡述我們是怎麼實作的......

3.1 理論基礎

工作流引擎的兩大子產品,一個是流程定義,一個是流程執行

現有的流程定義都是使用BPMN協定進行描述,這個協定實在是太龐大了,本着第一性原理,我們對工作流引擎的本質進行了深入的挖掘,重新對工作流進行了定義,提出了元模式的概念。

具體來講,詳細研究了43種工作流控制模式,這些工作流控制模式的組合基本上就能覆寫住絕絕絕大多數工作流場景,一般來講,對43種直接進行支援就可以了,但43種未免也有些過多,加上以後也會出現有44、45、46種模式,是以我們更進一步的對這43種進行泛化與抽象,最終得出了6種工作流控制元模式,通過這6種元模式的組合與API調用,就能夠直接或間接支援43種控制模式,同時,對未來出現的模式也有一定的支援,這6種為:

  • 事件:事用來表示發送一個事件,也可以表示等待接收一個事件,事件是廣播的方式傳播的
  • 活動:泛指各類活動任務,如:人工任務、腳本任務、服務任務、使用者任務、審批節點任務等,是與各個業務相關聯的
  • 子流程:也是一個流程,用來重用或消除重複、或者減少主流程的複雜性
  • 分裂:所有需要并行做的事情,都要用此元素,這裡并不規定分裂邏輯,以及分裂後的分支的數目
  • 彙聚:同步并行分支,在此之後,多條分支合并為一條,這裡也并不規定同步邏輯,以及多次同步的方法
  • 流轉:以上五種元素的流轉方向,一個源,一個目标,流程從源流轉到目标

如下圖所示:

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

對于流程執行來講,業内一般采用以下兩種技術:

  • 基于FSM的技術:由于FSM天生的缺陷,對于狀态的擴充能力較弱,應用面較窄,隻能在特定業務領域有較好的落地應用
  • 基于Token的技術:市面上最主流的技術,優點是理論模型較健全,缺點是落地較複雜,實作繁瑣,了解起來較困難

我們使用的并不是二者之一,而是基于無限狀态機模型的一種技術實作,如下圖:

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

這種技術的本質是個循環,其設計靈感來自于CPU的執行邏輯,不斷的讀取狀态,接下來對狀态進行處理,處理的結果也是一個狀态,然後繼續,直到沒有狀态或狀态暫時無法處理,這裡面還有個類似與中斷的喚醒狀态的邏輯,鑒于保密原則,此處不在展開

有了這些理論基礎,接下來就是落地實作了

3.2 工作流引擎架構

在落地實作的過程中,我們發現各種垂直業務領域的工作流都有着一些共性,同時也有着一些個性,而且,這些共性是架構次元的,并不是庫次元的,是以,我們對此進行了抽象,提出了工作流引擎架構的概念。具體來講,它是工作流引擎的模闆,通過使用這個架構,可以快速的開發實作各種業務域的“工作流”引擎,包括審批領域的審批流引擎、任務領域的任務流引擎、采購領域的采購流引擎等,它提供了基本的流程定義與流程執行能力,及其強大的擴充能力

有别于傳統的工作流引擎,它們對特定業務領域(如:審批流、任務流)的直接支援實在是太弱了,根本原因在于它們太通用了,通用到了為了支援各種工作流場景,把一塊木闆變成了木削,以至于當我要制造一個櫃子的時候,需要從木削開始加工,這極大的增加了工作量,在加上學習成本,可以說,這不是在提高效率,而是在降低效率。是以,一般來講,通用性越強,适用性越低,反之亦然。

具體到實作層面,架構一共分為兩層

第一層為ISM,也就是無限狀态機,是個微核心,其概念模型如下圖所示

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

Func是一個狀态轉換器,其有兩個方法,一個是transfer(),用來消費一個State,然後,生産一個State,另一個是eventHandle,用來消費一個消息,然後生産一個State;Funs維護着Func;Case是一個執行個體,其内部維護着所有的狀态(State),記錄着狀态變化的曆史,每一個狀态包含:

  • id:唯一辨別本狀态
  • tobeStarted:需要對本狀态進行處理的Func集合
  • ing:進行中的Func集合
  • toIngMsg:給進行中的Func發的消息
  • alreadySend:已經處理完消息的Func集合

第二層為PVM,也就是流程虛拟機,通過這個虛拟機可以進行流程定義、流程執行、與中斷喚醒等操作,如下圖所示

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

流程定義(Definition)繼承了Funcs,進而有了管理Func的能力,流程中的節點(Node)繼承了Func,進而有了消費與産出State的基本能力;由Transition來表示兩個節點之間的流轉,指定了來源節點與目标節點;流程執行個體(Instance),使用了流程定義,進而可以據此來發起一個流程,同時,也使用了Case,進行流程執行個體的流轉;對于節點來說,具象化了工作流領域内的常用的一些節點及其對狀态的處理邏輯,包括:

  • 活動節點Activity,以及以此為基礎的子流程節點SubProcess
  • 并發分裂網關Fork,以及與其配套使用的同步彙聚網關Join
  • 事件節點Event,以及其兩個重用分類,發送事件節點TxEvent,及其派生類EndEvent,接收事件節點RxEvent,及其派生類StartEvent

有了這個架構之後,就具備了基本的工作流流程定義與執行能力,能夠通過此來開發上層的審批領域的審批流引擎了

3.3 審批流引擎

審批流引擎設計到的點非常多,由于篇幅所限,這裡隻分享最重要幾點

第一個是在審批流流程定義層面,我們繼承了Activity節點,派生出了審批節點、抄送節點、填寫節點等

第二個是在API層面,我們直接提供了審批、同意、或簽、并簽、串簽、拒絕、駁回、回退到任意節點、前加簽、後加簽、平行加簽、平行減簽、外部調用節點、抄送、填寫、主子流程、分支、選擇、流程預測、流程仿真、取回、撤銷、傳閱等方法,可以直接調用

第三個是在流程執行層面,整個流程是個PVM,每個審批節點内部也有個PVM,這麼做的目的是因為審批業務的複雜性,同時也是一種現有能力的複用,由于PVM的足夠輕量,使得這種模式成為了可能,如下圖所示:

建構企業數字化轉型之某大廠審批流引擎核心技術揭秘

第四個是在流轉層面,每一次流轉的前後變化都存儲在一個上下文中,通過對比前後變化,就能夠得到一些資訊,包括:

  • 哪些節點已經開始執行了
  • 哪些節點已經完成了,包括取消
  • 哪些任務生成了
  • 哪些任務完成了,包括取消

進而,可以據此資訊來進行下一步的處理,如:持久化、回退等

第五個是通過通路者模式,提供了對流程定義合法性的發起前的檢查能力,同時提供了一些預設實作,也可自行擴充

第六個是直接提供了流程預測的方法,該方法實作的内在邏輯為:在記憶體中模拟整個流程的流轉,把其中涉及到的一些預測資訊存儲在一個Map中,這種方法有别于傳統的使用資料庫的方式,即快又不污染資料庫中的資料,同時也可并行執行,在預測過程中,不會阻塞正常流程的流轉

第七個是在節點擴充性方面,可以通過派生自審批節點的方式自行擴充自己特定審批邏輯的審批節點,也可通過派生自Activity、甚至是Func的方式,來擴充特定功能的節點

第八個是在分支條件表達式方面,對具體的表達式文法、語言進行了解耦,由其具體的表達式解析類進行表達式的解析,隻要把Bool結果告知引擎即可

第九個是對流程執行個體變量的弱化,弱化為一個Map,這樣可以表達更多的資訊

4. 未來展望

  • 在完善審批流引擎本身能力的同時,提供豐富的文檔與示例,友善大家使用
  • 基于審批流引擎,研發下一代審批流系統+,提供完善的內建能力,同時提供一些通用工作流能力
  • 建設審批流前端頁面元件能力,友善流程定義等前端複雜功能的實作