天天看點

自研規則/流程編排架構-ice簡介ice簡介

ice簡介

緻力于解決靈活繁複的寫死問題

官方文檔:http://waitmoon.com/docs

背景介紹

規則/流程引擎想必大家也都并不陌生,耳熟能詳的就有Drools,Esper,Activiti,Flowable等,很多大廠也熱衷于研究自己的規則引擎,都是用于解決靈活場景下的複雜規則與流程問題,想要做到改改配置就可以生成/生效新的規則,脫離寫死的苦海。畢竟改改配置和在已有基礎上編排規則/流程,比寫死的成本低很多,但是使用市面上現有的規則引擎來編排,一來接入成本和學習成本都不低,二來随着時間的推移,規則變的越發龐大以及一些場景的不适用,更加讓人叫苦不疊

場景

**會員營銷:**由多種條件,流程,獎勵組合而成,時間線複雜,代碼複用率不高,調整頻繁

**風控規則:**由多種條件組合并傳回決策,條件量大且複雜,變動頻繁

**資料分析:**将資料通過分析師自己編排的規則産出想要的資料,千人千面

以上場景往往都有一些共性:

靈活業務

追求靈活花裡胡哨:産品和營運一直在探索新鮮玩法,導緻很多抽象出來的子產品往往抗不過兩個疊代

今天上線又要調整:因為一些偶發情況,如線上使用者參與度不高,及時調整使用者參與門檻等(當然也可以在開發前把所有情況考慮到位,但是為了小機率事件做大量的工作,成本過高)

研發測試心力交瘁:研發寫死,測試測複雜重複邏輯,久而久之變的愈發疲憊

時間線

研發編排錯了再來:一般營銷類型的會涉及很多時間線,而在目前,測試一個未來要上線的具有不同時間節點屬性的活動,寫死時往往由研發編排時間,測試進行測試,但是當bug發生并打亂時間線時,就需要重新編排時間(沒有經曆過的不用太了解,後面會說)

測試并行孔融讓梨:當時間線發生沖突并有多個測試在沖突位置上并發測試,往往由測試自行協調測試順序,當一方出現問題往往導緻後續測試進度不可控

其他問題

依賴挂了難以為繼:測試環境為非穩定環境,一旦依賴出了問題難免影響進度,如何能做到簡單高效mock?

修複資料苦不堪言:當線上問題産生時,受影響的客戶如何快速高效的補償?

設計思路

為了友善了解,設計思路将伴随着一個簡單的充值例子展開

舉例

X公司将在國慶放假期間,開展一個為期七天的充值小活動,活動内容如下:

活動時間:(10.1-10.7)

活動内容:

充值100元 送5元餘額 (10.1-10.7)

充值50元 送10積分 (10.5-10.7)

**活動備注:**不疊加送(充值100元隻能獲得5元餘額,不會疊加贈送10積分)

簡單拆解一下,想要完成這個活動,我們需要開發如下子產品:

自研規則/流程編排架構-ice簡介ice簡介

圖中發現有待發放key,這個key是從哪裡來呢:

自研規則/流程編排架構-ice簡介ice簡介

如圖,當使用者充值成功後,會産生對應充值場景的參數包裹Pack(類Activiti/Drools的Fact),包裹裡會有充值使用者的uid,充值金額spend,充值的時間requestTime等資訊。我們可以通過定義的key,拿到包裹中的值(類似map.get(key))

子產品怎麼設計無可厚非,重點要講的是後面的怎麼編排實作配置自由,接下來将通過已有的上述節點,講解不同的規則引擎在核心的編排上的優缺點,并比較ice是怎麼做的。

流程圖式實作

類Activiti、 Flowable實作

自研規則/流程編排架構-ice簡介ice簡介

流程圖式實作,應該是我們最常想到的編排方式了~ 看起來非常的簡潔易懂,通過特殊的設計,如去掉一些不必要的線,可以把UI做的更簡潔一些。但由于有時間屬性,其實時間也是一個規則條件,加上之後就變成了:

自研規則/流程編排架構-ice簡介ice簡介

看起來也還好

執行樹式實作

類Drools實作(When X Then Y)

自研規則/流程編排架構-ice簡介ice簡介

這個看起來也還好,再加上時間線試試:

自研規則/流程編排架構-ice簡介ice簡介

依舊比較簡潔,至少比較流程圖式,我會比較願意修改這個。

變動

上面兩種方案的優點在于,可以把一些零散的配置結合業務很好的管理了起來,對配置的小修小改,都是信手拈來,但是真實的業務場景,可能還是要錘爆你,有了靈活的變動,一切都不一樣了。

理想

不會變的,放心吧,就這樣,上

現實

①充值100元改成80吧,10積分變20積分吧,時間改成10.8号結束吧(微微一笑,畢竟我費了這麼大勁,終于提現到價值了!)

②使用者參與積極性不高啊,去掉不疊加送吧,都送(稍加思索,費幾個腦細胞挪一挪還是可以的,怎麼也比改代碼再上線強吧!)

③5元餘額不能送太多,設定個庫存100個吧,對了,庫存不足了充100元還是得送10積分的哈(*卒…*早知道還不如寫死了)

以上變動其實并非看起來不切實際,畢竟小編我遇到的變動比這離譜的多的是,流程圖式和執行樹式實作的主要缺點在于,牽一發而動全身,如果考慮不到位,很容易被反噬,而且這還隻是一個簡單的例子,現實的活動内容要比這複雜的多的多,時間線也是很多條,考慮到這,再加上使用學習架構的成本,往往得不償失,到頭來發現還不如寫死。

怎麼辦?

ice是怎麼做的?

引入關系節點

關系節點為了控制業務流轉

AND

所有子節點中,有一個傳回false 該節點也将是false,全部是true才是true,在執行到false的地方終止執行,類似于Java的&&

ANY

所有子節點中,有一個傳回true 該節點也将是true,全部false則false,在執行到true的地方終止執行,類似于Java的||

ALL

所有子節點都會執行,有任意一個傳回true該節點也是true,沒有true有一個節點是false則false,沒有true也沒有false則傳回none,所有子節點執行完畢終止

NONE

所有子節點都會執行,無論子節點傳回什麼,都傳回none

TRUE

所有子節點都會執行,無論子節點傳回什麼,都傳回true,沒有子節點也傳回true(其他沒有子節點傳回none)

引入葉子節點

葉子節點為真正處理的節點

Flow

一些條件與規則節點,如例子中的ScoreFlow

Result

一些結果性質的節點,如例子中的AmountResult,PointResult

None

一些不幹預流程的動作,如裝配工作等,如下文會介紹到的TimeChangeNone

有了以上節點,我們要怎麼組裝呢?

自研規則/流程編排架構-ice簡介ice簡介

如圖,使用樹形結構(對傳統樹做了鏡像和旋轉),執行順序還是類似于中序周遊,從root執行,root是個關系節點,從上到下執行子節點,若使用者充值金額是70元,執行流程:

ScoreFlow-100:false

AND:false

ScoreFlow-50:true

PointResult:true

AND:true

ANY:true

這個時候可以看到,之前需要剝離出的時間,已經可以融合到各個節點上了,把時間配置還給節點,如果沒到執行時間,如發放積分的節點10.5日之後才生效,那麼在10.5之前,可以了解為這條調用鍊不存在(可以了解為這個節點還沒有上班,父節點不上班,綁在此父節點下面的邏輯也都不上班)

變動與問題的解決

對于①直接修改節點配置就可以

對于②直接把root節點的ANY改成ALL就可以(疊加送與不疊加送的邏輯在這個節點上,屬于這個節點的邏輯就該由這個節點去解決)

對于③由于庫存的不足,相當于沒有給使用者發放,則AmountResult傳回false,流程還會繼續向下執行,不用做任何更改

再加一個棘手的問題,當時間線複雜時,測試工作以及測試并發要怎麼做?

一個10.1開始的活動,一定是在10.1之前開發上線完畢,比如我在9.15要怎麼去測試一個10.1開始的活動?在ice中,隻需要稍微修改一下:

自研規則/流程編排架構-ice簡介ice簡介

如圖,引入一個負責更改時間的節點TimeChangeNone(更改包裹中的requestTime),後面的節點執行都是依賴于包裹中的時間即可,TimeChangeNone類似于一個改時間的插件一樣,如果測試并行,那就給多個測試每人在自己負責的業務上加上改時間插件即可。

特性

為什麼這麼拆解呢?為什麼這樣就能解決這些變動與問題呢?

其實,就是解耦,流程圖式和執行樹式實作在改動邏輯的時候,不免需要瞻前顧後,但是ice不需要,ice的業務邏輯都在本節點上,每一個節點都可以代表單一邏輯,比如我改不疊加送變成疊加送這一邏輯就隻限制在那個ANY節點邏輯上,隻要把它改成我想要的邏輯即可,至于子節點有哪些,不用特别在意,節點之間依賴包裹流轉,每個節點執行完的後續流程不需要自己指定。

因為自己執行完後的執行流程不再由自己掌控,就可以做到複用:

自研規則/流程編排架構-ice簡介ice簡介

如圖,參與活動這裡用到的TimeChangeNone,如果現在還有個H5頁面需要做呈現,不同的呈現也與時間相關,怎麼辦?隻需要在呈現活動這裡使用同一個執行個體,更改其中一個,另一個也會被更新,避免了到處改時間的問題。

同理,如果線上出了問題,比如sendAmount接口挂了,由于是error不會反回false繼續執行,而是提供了可選政策,比如将Pack以及執行到了哪個節點落盤起來,等到接口修複,再繼續丢進ice重新跑即可(由于落盤時間是發生問題時間,完全不用擔心活動結束了的修複不生效問題),同樣的,如果是不關鍵的業務如頭像服務挂了,但是依然希望跑起來,隻是沒有頭像而已,這樣可以選擇跳過錯誤繼續執行。這裡的落盤等規則不細展開描述。同樣的原理也可以用在mock上,隻需要在Pack中增加需要mock的資料,就可以跑起來。

引入前置節點

自研規則/流程編排架構-ice簡介ice簡介

上面的邏輯中可以看到有一些AND節點緊密綁定的關系,為了視圖與配置簡化,增加了前置(forward)節點概念,當且僅目前置節點執行結果為非false時才會執行本節點,語義與AND相連的兩個節點一緻

還有很多可以做的事情在這裡不在贅述,如果看到這裡并且還能了解的話,應該都會有一些想法(歡迎交流,哈哈哈)。

現行設計

理論有了,那就開整吧(本篇主要闡述思想,設計講解後續更新,先放兩張核心的結構圖)

節點類圖

架構中核心類關系圖:

自研規則/流程編排架構-ice簡介ice簡介

執行流程

請求處理和配置的拉取與更新過程:

自研規則/流程編排架構-ice簡介ice簡介

Code

Talk is cheap. Show me the code…

https://github.com/zjn-zjn/ice

還有很多細節功能和設計沒有寫出來,後續會考慮持續更新~

受限于作者能力問題,代碼暫時隻能寫成這樣了,哈哈哈,也會不斷的持續優化中~

有更好想法或者更多應用場景或者想一起探讨的小夥伴~ 歡迎交流(QQ群:587368939)~~