全鏈路營銷|基於事件驅動的流程編排系統 https://mp.weixin.qq.com/s/RHXyGaGyp_CK7FJPDqS3Cg
全鏈路營銷|基於事件驅動的流程編排系統
阿里妹導讀
本文主要介紹了 AE 策略中心的技術方案選型與落地實戰。
專案背景
全鏈路營銷是去中心化的運營方式,給使用者發放精細化的營銷權益,打造策略中心繫統。根據使用者的行為記錄使用者的喜好商品,在滿足策略中心規則後,透過 C 端鏈路的觸發實現營銷權益發放和權益表達。
架構設計
架構調研
當前營銷各應用都是採用 TMF 框架,由中臺提供標準的節點,營銷業務層進行節點編排,每個節點都提供相應的擴充點,可以讓不同營銷工具實現不同的營銷玩法。
上圖可以看出營銷計算的流程是比較固定的,業務迭代一般在當前流程的節點上進行擴充,TMF 提供的擴充點就是採用策略模式。比如文案構建節點,不同的營銷工具需要返回不同的文案,根據營銷工具型別匹配文案構建類,執行業務規則。
但是全鏈路營銷面向的是玩法層,所以每次迭代的業務流程都是不固定的,對使用者的行為要求是不固定的,對下游的依賴也是變化的。所以根據不同的玩法模板,執行不同的業務流程節點,這樣做後續的擴充性會比較好。
全鏈路營銷具有兩個鏈路:資料準備和權益發放,資料準備階段是使用者行為規則校驗透過後透過 MQ 訊息觸發,權益發放階段是在使用者在訪問某個資源位時,由上游呼叫策略中心觸發。
使用者的每個行為對我們來說都屬於事件,只不過有的是同步觸發,有的是非同步觸發,所以依賴不同的事件來編排不同的業務節點,編排方式可以透過配置中心或者 Java 硬編碼的形式,擴充性和靈活性更高,整體建設了一個基於事件驅動的流程編排系統。
系統架構
策略中心將不同事件透過不同的渠道(channelCode)進行標識,不同的 channelCode 觸發不同的流程編排。
策略中心的程式碼架構整體分為 4 層:
- 接入層:
- 使用者的行為校驗,由行為規則域統一收斂,滿足規則後傳送 MQ 訊息通知策略中心
- 使用者觸發某個資源位的行為,由上游同步通知策略中心
- 服務層:分渠道進行事件處理,然後統一調到領域層進行策略執行
- 領域層:策略域包含多個子域,可自主編排多個子域的域能力,最後對外提供策略域能力
-
基礎層:基礎設施層,包含外域依賴和儲存依賴兩個部分
流程設計
策略中心整體程式碼流程實現,如下圖所示:
- 行為事件:代表使用者完成了某個行為規則,MQ 訊息中攜帶 ruleKey 作為 channelCode,策略中心會透過渠道查詢策略活動,構建策略例項,完成資料的準備階段,包括查詢使用者操作的商品、演算法召回、處理商品折扣等,最後將策略例項的相關資料(商品、流程)儲存到 Redis。
-
資源位事件:代表使用者點選了某個資源位,API 的入參中有 channelCode,策略中心同樣進行活動查詢、策略構建,然後從 Redis 中讀取資料準備階段的資料,填充到策略例項,開始進行權益的發放。
設計說明:
- 策略例項的驅動邏輯固定,不同玩法對應不同的策略模板,模板會編排不同的節點形成執行器鏈,新增一種玩法只需要新增一個策略模板即可,不會對其他玩法產生影響,擴充性好。
- 分散式鎖保證同一個策略例項在同一時刻只能被一個執行緒執行,如果行為事件和資源位事件同時執行,會造成資料覆蓋的問題。
-
不涉及資料覆蓋問題的場景不需要加鎖,所以可以透過入參或者策略模板配置來決定是否加鎖。
模型設計
領域模型
策略域的聚合為 TacticsInstanceContext,也就是上文一直提到的策略例項,聚合根是 TacticsActivity 策略活動。每個策略例項 TacticsInstanceContext 中包含一個策略活動和相關的執行引數以及執行結果,執行引數包含買家 ID、渠道、是否加鎖、是否僅執行最優策略等資訊,所以一個策略活動和一個使用者唯一對應一個策略例項。
TacticsInstanceContext 只包含基礎的策略執行資料,但是策略層有多個子域,各個子域對 Context 的依賴不同,所以需要對策略例項做能力的擴充,常見的方式有:
-
Context 中提供 map 擴充欄位,將所有節點所需的資料統一放入擴充欄位中,Context 中提供充血方法獲取對應的資料。
-
提供能力擴充的介面,增加 Context 子類實現擴充介面,節點執行前判斷入參是否有該能力,在進行執行。
我們採用介面擴充的方式解決該問題,因為專案的核心設計思想就是策略 + 工廠模式,可以根據不同的策略模板(templateType)構建不同的 Context。
比如全鏈路營銷 3.0 版本需要使用者的商品資料,所以進行介面 IItemContext 的擴充:
策略模板
每種玩法對應一種策略模板,目前有全鏈路營銷 2.0 和全鏈路營銷 3.0 兩個模板,所以透過模板工廠去獲取模板的配置:
上圖可以看出,getProcessorChain() 提供了核心的流程編排能力,因為每個事件對應一個 channelCode,所以流程編排是基於事件標識來完成,程式碼示例:
public List<String> getProcessorChain(String channelCode) {
List<String> processorChain = Lists.newArrayList();
// channelCodeA 或 channelCodeB 理論上都是一個可配置的Set集合,這裡進行簡化
if ("channelCodeA".equals(channelCode)) {
// 查詢商品
processorChain.add(QueryacticsProcessor.PROCESSOR_NAME);
// 處理商品營銷資料
processorChain.add(HandleItemPromotionTacticsProcessor.PROCESSOR_NAME);
// 記錄行為事件消費成功
processorChain.add(EventTacticsProcessor.PROCESSOR_NAME);
} else if ("channelCodeB".equals(channelCode)) {
// 校驗行為事件是否消費成功
processorChain.add(CheckEventTacticsProcessor.PROCESSOR_NAME);
// 規則校驗
processorChain.add(RuleCheckTacticsProcessor.PROCESSOR_NAME);
// 查詢資產
processorChain.add(QueryAssetTacticsProcessor.PROCESSOR_NAME);
// 權益發放
processorChain.add(SendBenefitTacticsProcessor.PROCESSOR_NAME);
// 構建結果
processorChain.add(BuildResultTacticsProcessor.PROCESSOR_NAME);
}
return processorChain;
}
節點模型
介面類:
public interface TacticsProcessor {
/**
* 節點名稱
*/
String getProcessorName();
/**
* 策略例項匹配校驗
*/
boolean validate(TacticsInstanceContext instanceContext);
/**
* 策略例項執行邏輯
*/
void process(TacticsInstanceContext instanceContext);
}
擴充子類:
冪等設計
業務玩法是迴圈發放權益,但是隻有當前使用者不存在可用的資產(未領取、過期、核銷等),才進行發放。
權益系統可以保證一個冪等 ID 只會進行一次的資源扣減和資產的寫入動作,並且當一次請求失敗時,權益系統內部會主動重試或回滾,所以策略中心為了防止超發問題,做了兩件事:
- 保證冪等 ID 的唯一性,可重入性;
-
當存在可用的資產時,直接返回該資產,不進行權益發放;
當使用者資產表查詢出現抖動或者其他情況時,我們將發放的次數置為 0,第幾次發放 willSendCnt 置為 1。如果使用者是第一次領取,那麼會執行真正的權益發放,符合業務流程;如果使用者非首次領取,因為相同的冪等 ID 只會扣減一次資源,所以不會造成超發。
專案總結
本文主要介紹了 AE 策略中心的技術方案選型與落地實戰。從最初版的邏輯平鋪的技術設計,到基於事件驅動的流程編排系統,我們做了系統架構的最佳化和提升,未來可擴充性更強,業務迭代只需要增加新的的策略模板和節點即可,不會影響其他策略模板邏輯,符合開閉原則。