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