開發與維運

如何在端外投放的場景下實現前端實時CEP框架?

作者:閒魚技術-玉縝

背景

複雜事件處理(Complex Event Processing,以下簡稱CEP)在閒魚內得到了廣泛應用,基於用戶使用閒魚的實時行為,為用戶提供更加豐富的優質信息與服務。閒魚技術公眾號有介紹過CEP在服務端和客戶端上的設計與實現。然而之前的設計方案都只適用於閒魚App端內場景,針對端外投放拉新場景(例如用戶訪問了多個商品詳情頁之後給用戶發放優惠引導用戶下單)需要設計在純前端環境執行的實時CEP框架。本文主要介紹了在前端實現CEP的相關設計與實現。

設計目標

整個流程可以抽象為用戶實時行為按照一系列規則匹配之後,以前臺UI的方式對用戶進行觸達干預。對外投業務場景進行抽象,除了CEP基礎能力之外,還有這三點關鍵設計目標:

  1. 觸達實時:從用戶相關行為操作到對用戶進行觸達干預要儘量快,如果整個流程不夠快,在觸達干預的時候用戶可能已經流失了。
  2. 策略動態:業務需要經常對線上策略進行調整,期望業務開發只需要做一次接入,後續策略都可以服務端動態下發。
  3. 多容器:外投場景包括小程序/Web/Weex這幾種容器場景,都需要支持。

架構設計

將業務流程拆解為三部分,分別是用戶實時行為採集、對實時行為按照規則複雜計算、以前端UI組件進行用戶觸達,對應三個核心模塊:事件採集、複雜計算和用戶觸達。針對上述設計目標,為了實現觸達實時,將對行為的複雜計算放到前端去執行;為了實現策略動態,設計了一個服務端運營平臺管理所有策略,採集行為信息、複雜計算規則、觸達組件信息都從服務端獲取;為了實現多容器,將實時行為採集和UI組件觸達進行標準設計,分不同容器環境實現。此外由於策略會存在跨頁面的場景,底層會有數據同步模塊同步行為數據和計算狀態。下面分別對重要模塊進行詳細介紹。
|center

事件採集

事件採集模塊將用戶行為轉化為標準事件。首先是用戶行為無侵入採集,無侵入採集是為了解決兩個問題,第一個是為了讓業務開發接入更加簡單,不需要手動調用採集代碼;第二個是為了覆蓋更多可能的採集點,利於後續策略動態下發。這裡我們選用靜態掃描代碼的方式,在具有特定行為標示(例如onClick)的元素節點上注入採集參數,採集參數通過元素樣式名稱、組件名稱、文件路徑等信息生成,具有比較好的語義;並且和運行時無關,更利於擴展不同容器實現。
|center|321x400
初期先定義了用戶基礎操作行為(enter、leave、scroll、appear、click),用戶行為多樣並且形態複雜,因此首先需要將用戶行為做標準化處理。此外隨著業務使用後續有一些業務模塊也要事件形式進入計算,例如http請求返回的結果也會作為一個事件,因為這裡設計了一個插件機制,能夠讓業務模塊快速轉化成標準行為。

複雜計算

目前社區前端複雜計算相關方案都比較簡單,不適用於業務場景。自研上選擇參考業界CEP標準實現,業界CEP設計主要源於這篇論文Efficient Pattern Matching over Event Streams,在這篇文章裡介紹了CEP的核心是NFA(不確定的有限狀態機),CEP的匹配過程就是NFA狀態變化的過程。因此首先在前端實現了一個NFA類,實現這樣一個狀態機。
|center
但是我們無法直接創建一個NFA去描述匹配規則,更習慣按照事件間關係與每個事件的匹配規則去定義,因此需要在上層封裝一套API來創建NFA。這裡參考了Flink CEP Pattern API的設計。通過next/followedBy/followedByAny/notNext/notFollowedBy等API來定義事件間關係,通過where/and/or等API來定義每個事件的匹配規則。通過Pattern定義會生成一箇中間鏈表,生成NFA的過程就是反向解析這個鏈表。
|center
前端做複雜計算我們總會擔心性能是否有問題。以下面這個性能壓測為例,有20個策略在做匹配的情況下,一次灌入200條行為數據,整體耗時在3.73s。雖然時間並不是特別長,但是由於瀏覽器運行機制,JS引擎線程在執行的情況下,UI渲染線程也會被掛起,在這3.73s內用戶所有在頁面上的操作都得不到響應,感覺就是“卡住了”。因此前端複雜計算性能優化更多需要考慮計算過程中不能影響用戶體驗。
|center
對比目前業內的解法,Worker和Webassembly存在容器限制以及優化效果可能不明顯。這裡選用了一種時間切片的解法,整體思路和React Fiber機制比較類似。將複雜計算的大任務拆解為小任務執行,在小任務執行完之後,會適當讓出JS主執行線程的控制權,讓瀏覽器能夠響應用戶操作,保證用戶操作不受影響。下面這張圖是優化後的效果,可以看到每個任務執行之後有一段空閒。並且這個優化方式是純JS層面的優化,不受單一容器的限制。
|center

用戶觸達

用戶觸達模塊管理用戶前臺展示組件,出於對bundle大小的考慮,組件代碼都通過動態加載的方式。由於需要針對不同容器實現,在上層統一標準組件的設計,包括統一組件API、輸入數據源以及埋點信息等。組件相關設計最終會影響各容器實現成本和業務效果統計。

數據同步

由於跨頁面場景(例如訪問了詳情頁又訪問了這個賣家的閒魚號)存在,而前端多個頁面之間不具備通信能力,也不存在一個線程在後臺一直處理業務邏輯,因此在行為數據以及計算狀態的同步上需要依賴本地存儲能力。前端本地存儲都只支持Key/Value存儲,能力相對較弱,頻繁讀寫數據容易出錯。因此在本地存儲上層實現一層內存緩存,擴展了一些存儲能力,每隔一段時間或者在一些時間節點上(例如離開頁面)和本地存儲同步,這樣既保證了存儲的靈活性,又實現了跨頁面數據同步。

未來展望

目前該前端CEP框架已投入線上業務使用,在阿里小程序、Weex、Web下都能良好運行,並且提供了一定的運營配置能力,在目前線上單一策略下整個流程可以在毫秒級內完成,後續在業務上會有更廣泛的使用。
在技術細節以及業務易用性上,我們依然有很多可以完善的地方,後續的一些演進方向如下:

  1. 端內外全鏈路觸達:與服務端、客戶端在行為定義、規則計算、觸達干預上統一一套標準協議,在閒魚端內外全鏈路上此類問題通過統一一個系統承接。
  2. 運營體系完善:讓業務更加便捷構建策略投放,在數據挖掘上能夠更好輔助業務做決策。
  3. 智能化:將目前依據業務經驗的規則匹配向算法根據用戶行為智能決策轉化,同時探索前端智能化的可能性。

Leave a Reply

Your email address will not be published. Required fields are marked *