流程架構演進:從裸用Activiti到統(tǒng)一流程平臺)
1. 從裸用 Activiti 到建設流程平臺一次架構演進復盤先說背景。我過去幾年帶團隊做過不少企業(yè)內部系統(tǒng)的流程模塊早期項目圖省事直接在業(yè)務代碼里嵌 Activiti部署一個流程就塞一個流程定義所有審批邏輯都往引擎里寫。前兩年還好等流程數量一多、參與方一雜問題就全冒出來了流程定義散落在各個服務里、發(fā)起和審批入口五花八門、改一條流程要發(fā)版上線、跑掛一個節(jié)點連日志都找不到。到了后面光靠 Activiti 的 API 已經撐不住整個企業(yè)的流程訴求了。這篇博文就圍繞一條主線怎么從“業(yè)務系統(tǒng)里用 Activiti”過渡到“統(tǒng)一的企業(yè)流程平臺”。我會先復盤裸用階段踩過的坑再講平臺化改造時的架構設計、核心模塊拆分、幾個關鍵落地細節(jié)包括 Activiti 數據庫版本選型、離線插件安裝這類很具體的問題最后把線上實施過程中遇到的典型故障和排查思路整理成一份速查表。如果你現在正處在“流程代碼越寫越多、卻感覺越來越難維護”的階段這篇文章應該能幫你看清楚問題出在哪以及從哪兒下手去做升級。2. 為什么非要從 Activiti 走向流程平臺2.1 裸用 Activiti 的典型痛點先說場景。大部分團隊第一次接觸 Activiti都是因為業(yè)務里需要審批流。最常見的做法是在訂單、報銷、合同這類應用里引入 Activiti 依賴然后自己封裝一層 Service誰要發(fā)起流程就調用一下誰要審批就查一下任務列表。前期只有兩三條流程的時候這套玩法效率很高因為 Activiti 對 BPMN 2.0 規(guī)范的支持非常完整流程定義管理、任務分配、流程變量、歷史數據它全都幫你做掉了。但隨著流程數量增長幾個問題會越來越明顯。第一流程定義和業(yè)務系統(tǒng)強耦合。每條流程的 bpmn 文件放在各自工程里改了要跟著業(yè)務服務一起打包發(fā)版。哪天產品提了一句話說“合同審批的第三級審批人換成部門總監(jiān)”本意是個五分鐘的配置改動結果你愣是得走一次發(fā)布流程。第二執(zhí)行引擎分散。好幾個服務各自引入 Activiti等于跑了好幾套流程引擎每個引擎維護自己的 ACT_* 表跨系統(tǒng)的流程協(xié)同根本做不了。第三監(jiān)控和排查能力約等于零。流程實例卡在哪個節(jié)點哪個環(huán)節(jié)耗時最長有沒有異常重試機制這些在裸用階段基本靠手工翻數據庫。2.2 流程平臺要解決什么問題所以做流程平臺本質上不是“換掉 Activiti”而是“把 Activiti 收編到平臺內部”讓業(yè)務系統(tǒng)不再各自為戰(zhàn)。這里面的核心轉變有三個。一是角色轉變。原來 Activiti 是嵌在業(yè)務代碼里的一個組件改造后它變成了平臺層的基礎引擎對外提供統(tǒng)一的服務能力。業(yè)務系統(tǒng)不再直接觸碰 engine API而是走平臺提供的接口。二是能力補齊。Activiti 本身解決的是流程執(zhí)行問題但它不關心流程怎么設計、怎么管理、怎么監(jiān)控、怎么統(tǒng)計。流程平臺要在引擎外面補上這些能力可視化流程設計器、統(tǒng)一流程管理后臺、流程實例監(jiān)控、超時提醒、SLA 統(tǒng)計、組織權限同步等等。三是標準統(tǒng)一。所有業(yè)務流程都通過平臺發(fā)起和流轉流程定義統(tǒng)一管理任務統(tǒng)一處理接口統(tǒng)一規(guī)范。這樣不管是新的審批需求還是對接外部系統(tǒng)都有了一套標準的接入方式而不是每個項目自己造一套輪子。3. 流程平臺的整體架構設計與能力規(guī)劃3.1 平臺分層架構怎么定在做架構設計的時候我沒有一上來就寫代碼而是先定了一個原則平臺要跟業(yè)務系統(tǒng)解耦但也要讓業(yè)務系統(tǒng)接入得足夠輕。最后落地下來的分層結構大致是這樣的。接入層對外提供統(tǒng)一的 REST API 和消息通道主要解決身份認證、參數校驗、接口鑒權這些通用問題。不管是內部系統(tǒng)還是外部系統(tǒng)接入流程平臺都走這一層不允許有人繞過平臺直接調引擎。服務層是平臺的業(yè)務核心流程定義管理、流程實例管理、任務管理、委派轉辦、駁回跳轉、會簽票簽這些能力都在這一層封裝對上屏蔽引擎細節(jié)。引擎層就是 Activiti負責 BPMN 解析、流程驅動、任務分配、事件觸發(fā)這些標準能力。管理端是運營和配置人員的入口負責流程設計、部署、權限配置、監(jiān)控告警。存儲層除了 Activiti 自身的 ACT_* 表還增加了平臺自己的業(yè)務表用來存流程分類、表單綁定關系、操作日志、流程與業(yè)務單據的關聯關系。這個分層結構其實參考了業(yè)界做流程平臺比較通用的模式。重點不在架構圖本身多好看而在“邊界要清晰”引擎就是引擎平臺就是平臺業(yè)務系統(tǒng)就是業(yè)務系統(tǒng)誰也別跨界。3.2 核心模塊拆解平臺化改造過程中我覺得有五個模塊是必須認真做的缺一個后面都難受。流程設計器。設計器是給流程管理員用的不是給程序員用的。所以不能直接丟個 Activiti Modeler 給業(yè)務人員那樣他們光畫網關和事件就會懵。我們的做法是基于 bpmn-js 做了一套簡化版設計器默認只暴露開始事件、用戶任務、排他網關、結束事件這幾種常用要素其他高級元素在高級模式下才展示。設計器最終生成標準的 BPMN 2.0 XML保存到流程定義庫。流程定義管理。這個模塊管的是流程的“版本、分類、狀態(tài)、權限”。部署新版本的時候設置為待發(fā)布狀態(tài)確認沒問題再激活。已經發(fā)起的老流程繼續(xù)使用舊版本新發(fā)起默認走新版本這是 Activiti 本身就支持的版本機制平臺要做的就是把它合理地暴露出來。統(tǒng)一任務中心。每個業(yè)務系統(tǒng)都有一套自己的待辦列表這是常態(tài)。平臺要做的不是取代業(yè)務系統(tǒng)的待辦而是提供統(tǒng)一的任務查詢和操作接口。待辦數據通過消息實時同步給業(yè)務系統(tǒng)業(yè)務側只需要接收數據做展示真正的審批動作統(tǒng)一回寫平臺。實例監(jiān)控與運維。這是裸用 Activiti 時最缺的能力。平臺要能實時看到每個流程實例走到哪個節(jié)點、當前處理人是誰、這個節(jié)點停留多久、有沒有超時告警。Activiti 的引擎事件監(jiān)聽器就是做這件事的抓手通過監(jiān)聽任務創(chuàng)建、任務完成、流程結束這些事件把數據加工后寫入平臺的監(jiān)控表再配合定時任務做超時檢測。組織與權限同步。企業(yè)流程離不開組織架構但 Activiti 自帶的 ACT_ID_* 身份體系一般不建議直接用。原因很簡單企業(yè)內部的組織架構基本上都在統(tǒng)一的權限系統(tǒng)里維護流程平臺要是自己再維護一套身份數據很快就會出現“人已經離職了流程還在給他審批”這種尷尬事。我們的方案是平臺只保存一份與上游同步過來的用戶、部門、角色的簡化副本每次同步做全量比對增量更新審批人的解析統(tǒng)一通過同步數據完成。3.3 方案選型為什么繼續(xù)用 Activiti沒有換成別的引擎這塊我多說幾句。改造過程中有不少同事提過要不要干脆換掉 Activiti用 Flowable、Camunda 或者自研一套。我的建議是不要輕易換引擎。原因有三點。第一Activiti 的成熟度和社區(qū)基礎在 Java 技術棧里仍然很能打BPMN 2.0 的完整支持、豐富的 API、數據庫表結構設計都很穩(wěn)定團隊里很多開發(fā)對它已經足夠熟悉。第二流程平臺的核心競爭力根本不在引擎本身而在引擎之上封裝的產品能力、集成能力和運維能力。換一個引擎不會讓你的平臺更好用反而要承擔巨大的遷移和兼容成本。第三Activiti 7 的版本在擴展性和云原生適配方面都有了改進夠用。所以我的建議是引擎層面穩(wěn)定優(yōu)先不要為了“技術新”去冒風險平臺的價值要靠上層能力和工程治理來體現。4. 實操關鍵版本、數據庫、離線插件與二次封裝4.1 Activiti 數據庫版本選型與表結構差異Activiti 的數據庫版本問題是很多團隊容易忽略的重災區(qū)。Activiti 5.x、6.x、7.x 的 ACT_* 表結構有差異尤其涉及到歷史數據和流程實例的平滑過渡絕不能拍腦袋升級。我這里列一個最簡單的對照表。版本主要變化升級注意點5.x經典的 ACT_RE_/RU_/HI_/ID_ 結構早期版本大量項目使用升級需腳本遷移6.x表結構微調、JSON 支持增強與 5.x 不兼容需要完整遷移流程定義和歷史數據7.x模塊化重構支持 Spring Boot 2.xAPI 變化明顯依賴引入方式變化大我們平臺最終選的是 7.x 線。原因很簡單項目技術棧是 Spring Boot 2.xActiviti 7 的 starter 集成最順暢而且模塊化做得比 6.x 清晰適合在這之上做二次開發(fā)。但這里有個很關鍵的坑Activiti 的自動建表機制在生產環(huán)境要關掉。在 application.yml 里配置spring: activiti: database-schema-update: false db-history-used: true history-level: audit生產環(huán)境強烈建議顯式關閉 schema 自動更新由 DBA 審核腳本后手動執(zhí)行。歷史級別按需選擇如果流程不需要精細化追溯用 audit 就夠了full 級別會記錄所有變量變化數據量增長非???。4.2 關于 Activiti 數據庫表的核心理解聊數據庫版本有個問題繞不開Activiti 啟動后自動生成的那幾十張表都是干什么的如果這一層搞不清楚后面排查問題會非常被動。我通常把 Activiti 的表分成四類。資源與定義類主要是 ACT_RE_ 前綴比如 ACT_RE_PROCDEF 存流程定義信息ACT_RE_DEPLOYMENT 存部署記錄。運行時數據類主要是 ACT_RU_ 前綴像 ACT_RU_EXECUTION 存執(zhí)行實例信息ACT_RU_TASK 存當前待辦任務ACT_RU_VARIABLE 存流程變量這類表是流程引擎運行時的核心數據會隨著流程結束被清理。歷史數據類主要是 ACT_HI_ 前綴流程實例歷史、任務歷史、活動歷史、變量歷史都在這里數據只會增加不會減少是需要重點做數據治理的部分。通用數據類主要是 ACT_GE_ 前綴像 ACT_GE_BYTEARRAY 存 BPMN 文件的二進制內容ACT_GE_PROPERTY 存引擎版本和 ID 生成相關的屬性。理解這四類表的生命周期差異很重要運行時表要關注性能避免大量積壓歷史表要關注容量定期歸檔和清理。很多團隊流程跑一段時間數據庫就變慢了十有八九是歷史表膨脹導致的。4.3 IDEA Activiti 插件離線安裝的實踐再說一個開發(fā)期很實際的問題IDEA 里 Activiti 插件離線安裝。很多企業(yè)內部開發(fā)環(huán)境是不能訪問公網插件市場的但畫 BPMN 文件又確實需要可視化工具。這里分享一個可靠的離線安裝路徑。第一步找一臺能上網的機器到 IDEA 插件市場下載對應版本插件包。以 Activiti BPMN visualizer 為例在插件市場頁面選擇與你 IDEA 版本兼容的版本號下載 .zip 格式插件包。第二步把插件包拷貝到內網開發(fā)機。第三步打開 IDEA 的 Settings進入 Plugins點擊齒輪圖標選擇 Install Plugin from Disk選中插件包后重啟 IDEA。需要特別留意的是插件版本跟 IDEA 版本有嚴格的兼容性裝完后右下角提示插件不兼容多半是版本選錯了。另外離線安裝雖然省去了網絡問題但插件自身的依賴不會自動補全所以盡量選擇功能完整、無額外運行時依賴的插件。如果你只是需要一個輕量的查看器用 IntelliJ 自帶的 Diagram 也能臨時頂一頂但編輯 BPMN 還是用專門的 Activiti 插件效率高。4.4 對 Activiti 引擎做二次封裝平臺層對 Activiti 的封裝我建議把握一個度不是所有的引擎 API 都要暴露出去而是只暴露業(yè)務真正關心的那幾種能力。統(tǒng)一的流程發(fā)起接口、統(tǒng)一的審批操作接口、統(tǒng)一的流程查詢接口這三類是最基本的。舉個例子我們封裝發(fā)起流程的接口時參數里包含流程定義 Key、業(yè)務單據 ID、發(fā)起人、審批變量。平臺內部做這幾件事根據定義 Key 獲取最新版本定義、創(chuàng)建流程實例并綁定業(yè)務 Key、記錄業(yè)務系統(tǒng)與流程實例的關聯關系、初始化流程變量。審批操作同樣如此。對外只提供一個 complete 接口內部根據當前任務節(jié)點類型做不同處理普通用戶任務直接 complete會簽任務處理票簽邏輯網關節(jié)點自動流轉。這樣對業(yè)務系統(tǒng)來說所有審批都只有“提交”一個動作復雜度全被平臺吸收了。封裝的時候還要特別注意事務邊界。Activiti 的操作跟業(yè)務系統(tǒng)的事務不在一個事務上下文里如果平臺只管調引擎不考慮業(yè)務數據的一致性就會出現“業(yè)務單子成功了但流程沒發(fā)起”或者反過來“流程走了一半業(yè)務數據沒存上”的情況。我們的方案是提供事務模板接口業(yè)務系統(tǒng)在同一個事務里先寫業(yè)務數據、再調用流程接口平臺內部通過同步事務狀態(tài)來保證數據一致。5. 實施過程中的坑與排查實錄5.1 常見問題速查表這部分我整理了一份速查表都是從實際項目里總結出來的比看文檔印象深得多?,F象可能原因排查方法流程實例沒有按預期流轉排他網關條件未覆蓋所有分支檢查 BPMN 條件表達式與流程變量類型待辦任務突然消失任務被其他節(jié)點串簽/會簽處理查看歷史任務表追蹤任務生命周期引擎啟動報表不存在錯誤關閉了自動建表但沒有初始化腳本手動執(zhí)行對應版本的 create 腳本歷史表數據增長很快history-level 設置過高調整級別增加定期歸檔任務發(fā)起流程時接口超時流程實例數過多導致引擎性能下降檢查運行時表數據量、索引命中情況同一個流程實例重復發(fā)起業(yè)務系統(tǒng)未做冪等處理增加唯一業(yè)務 Key 與事務控制5.2 幾個印象深刻的線上案例我挑兩個親歷過的問題展開講講。第一個是流程不會自動流轉的問題。現象是某條合同審批流在第一個審批節(jié)點通過之后第二個節(jié)點一直沒有生成待辦。我查了流程實例運行表發(fā)現執(zhí)行實例確實停留在第一個網關前。后來逐行看 BPMN XML發(fā)現問題出在排他網關的條件表達式上。流程變量是一個 Integer但 BPMN 條件里寫的是字符串比較類型不匹配導致條件永遠為 false網關沒有出口可選流程自然就卡住了。解決方式很簡單統(tǒng)一條件表達式的類型轉換規(guī)則。但這之后我在代碼審查里加了一條硬性要求流程條件里的變量類型必須在流程啟動時強制確認不允許隱式轉換。第二個是歷史數據膨脹引發(fā)的性能問題。上線三個月后有業(yè)務系統(tǒng)反饋流程發(fā)起接口越來越慢。查了一圈發(fā)現不是引擎本身的問題而是 ACT_HI_VARINST 表已經積壓了一千多萬行聯合查詢性能急劇下降。后來我們做了一套完整的歸檔方案每天定時把三個月前的歷史數據遷移到歸檔庫業(yè)務查詢走歸檔庫在線庫只保留熱數據。這個例子想說明的是用 Activiti 做流程平臺數據庫數據治理一定要前置設計不要等到線上出問題了才回頭補。5.3 事務一致性和性能調優(yōu)的兩個經驗再講兩個容易被忽視的細節(jié)。事務一致性是流程平臺必須正視的問題。Activiti 內部操作有自己的事務管理如果業(yè)務系統(tǒng)在同一個流程操作里還要更新自己的業(yè)務表就涉及到跨數據源事務不能簡單依賴 Spring 默認的本地事務。我推薦的做法是盡量保證“一個操作只寫一個數據源”要么先寫業(yè)務數據、成功后通過異步消息觸發(fā)流程要么先發(fā)起流程、在流程回調里寫業(yè)務數據。如果必須要同步強一致再考慮引入分布式事務方案但盡量避免因為復雜度太高。性能調優(yōu)方面Activiti 7 的默認配置在大部分場景下是夠用的但如果流程實例并發(fā)量很高有幾個參數值得去調。異步執(zhí)行器的核心線程數、最大線程數和隊列容量決定了引擎處理異步事件的能力歷史數據清理任務建議放到業(yè)務低峰期執(zhí)行避免占用數據庫資源。另外所有高頻查詢接口都要注意運行時表和歷史表的索引索引缺失在數據量不大的時候沒什么感覺數據量一上來就是災難。6. 平臺上線后的運維治理與演進方向6.1 監(jiān)控指標與告警體系流程平臺上線的第一天就要把監(jiān)控體系鋪起來。我的經驗是分三個維度來做。第一個維度是引擎健康度。Activiti 引擎自身能不能正常工作包括引擎啟動時間、異步執(zhí)行器隊列積壓量、流程引擎數據庫連接池使用率。第二個維度是流程運行指標。按流程定義維度聚合統(tǒng)計發(fā)起量、完成量、平均耗時、超時率。這些指標能從數據上反映哪條流程需要優(yōu)化比如某條流程的平均耗時明顯偏高那大概率是審批環(huán)節(jié)配置不合理或者有節(jié)點處理人缺失。第三個維度是業(yè)務異常監(jiān)控。包括任務創(chuàng)建失敗、流程實例異常結束、事件監(jiān)聽處理失敗。告警規(guī)則不用一開始就設得很復雜先把最核心的幾條配上流程實例異常終止、異步任務積壓超過閾值、任務停留超過 SLA、數據庫連接池耗盡。告警渠道最好能接入企業(yè)統(tǒng)一告警中心不要自己單獨搞一套。6.2 從流程平臺到流程體系的演進平臺穩(wěn)定運行一段時間之后可以開始思考更高一層的事情。我比較看好的方向有兩個。一個是流程分析與優(yōu)化。平臺積累了大量的流程運行數據可以從數據里去發(fā)現流程瓶頸。比如報銷流程平均要走五級審批但數據顯示超過一半的審批節(jié)點耗時不到一分鐘說明這些節(jié)點只是走個形式完全可以精簡掉。這就是數據驅動流程優(yōu)化的典型場景。另一個是流程資產化。當流程平臺覆蓋了企業(yè)核心業(yè)務流程之后流程本身就成了企業(yè)的數字化資產。新業(yè)務系統(tǒng)上線時不用再從零開始設計流程而是從平臺已有的流程資產庫里選擇、組合、復用。這個階段平臺的價值就不只是“跑流程”了而是上升到了企業(yè)運營基礎設施的層面。7. 最后的一些心里話我個人在實際項目中最大的一個體會是流程平臺不是一個一次性的技術項目它更像是一個隨著企業(yè)業(yè)務演化而持續(xù)生長的底座。建好一套流程架構很容易難的是讓團隊真正愿意把流程都沉淀到平臺上來這背后涉及組織協(xié)同、權限梳理、歷史系統(tǒng)遷移比技術本身難得多。另外還想提醒一點無論你做得多完善永遠會給后續(xù)的迭代留出空間。Activiti 的版本會持續(xù)更新平臺的接入規(guī)范也會不斷調整一開始就把架構做死了后面反而寸步難行。保留核心抽象靈活性讓新流程接入的成本盡可能低才是這套架構能長期走下去的關鍵。如果這篇文章里的經驗能讓你在規(guī)劃企業(yè)流程架構升級時少走幾個彎路那就值了。