效率消息中心從0-1搭建與思考
1、什么是消息中心
消息中心是一個集中管理、分發通知和提醒的平臺,可以讓用戶或系統消息更方便、快捷的觸達給指定用戶或者系統。并且可以幫助用戶或系統更好地管理消息的生命周期,屏蔽不同消息渠道差異與技術差異,從而提升效率與體驗,降低維護成本。
2、為什么要搭建消息中心
- 公司目前處于快速發展階段,業務線正在快速拓展,不同的產品線也正在逐步增加,與此同時,不同的產品線均需要通過消息模塊來觸達內部或外部用戶,基本上每一個系統都需要有自己的消息通知體系。但在由于不同業務開發團隊相互獨立,為了避免協調溝通這種不可預估的成本,各業務開發團隊都采取了“自主”開發的方式解決此類問題。這樣造成的結果就是:各業務團隊不斷地重復發明輪子,而且這輪子不可復用,造成了資源和時間成本的大量浪費。更為關鍵的是:功能無法復用,持續迭代也無法沉淀。當面對一個新業務時,即便公司已有成熟的功能,但仍然無法有效地縮短業務創新和推進的時間。
- 各業務系統均以功能的概念在設計,業務資源和開發資源會存在大量的重復消耗,在維護方面也存在諸多問題,并且不利于統一管理,并且也沒有相關消息觸達統計與數據分析能力。 為了適應公司的業務發展以及未來不同場景下的消息應用,我們將引入消息中心概念,抽取通用和穩定的部分劃歸到消息中心來實現,拆解模塊之間的職能,解決重復造輪子,反復改問題的現象。同時將不同的消息渠道整合,為不同的業務線提供不同場景的應用支撐?;诖吮尘?,我們搭建了一個基于內部系統的消息中心。
3、設計與思考
3.1 業務系統架構
應用架構這里就不展示了,因為是基于技術部中間件團隊java應用(nvwa)工廠生成標準COLA的多模塊項目模板應用。
3.2 消息流程管理
消息通知的流程設計,在各個業務線中通過消息中心提供的接口方法,將不同場景下的消息內容提交到消息中心,消息中心進行統一維護管理,并根據消息的來源和去向,適配相應的推送邏輯:
- 消息生產:涉及到的場景很多,比如活動、系統通知、業務流轉、過期提醒等;
- 消息管理:對預發送消息的結構和參數進行校驗,并創建消息推送的任務,維護任務級別的推送管理,跟蹤消息的狀態周期;
- 消息處理:基于消息任務的結構,構建消息推送的主體內容,并對接多個發送渠道,實現通知的高效觸達;
- 定時任務:消息可以直接即時推送,但如果是夜間定時任務觸發,則要考慮推送延遲問題,將消息放在指定時段投遞;
- 渠道對接:通常不同的渠道意味著不同的場景,例如監控推送飛書,郵件走email,業務則應用內通知;
在整個流程中涉及到的模塊比較多,狀態的流轉也很復雜,但是通過消息中心進行統一標準管理和流入流出的跟蹤,也可以提供清晰的生命周期監控和維護。大部分的消息通知機制都可以容忍一定的延遲性,所以消息中心完全可以解耦各個流程,引入MQ隊列或者異步機制,業務方只需要將請求發送到消息中心,之后由消息中心統一調度和管理即可。
3.3 數據模型
3.4 飛書通道與業務系統對接過程中遇到的問題
3.4.1 老應用有增量消息需接入效率消息中心,效率消息中心該如何解決歷史消息轉發及復雜交互類型消息的事件回調。
飛書側機器人回調地址只能填寫一個,歷史的應用已經對接過飛書平臺進行發消息,對于系統增量消息想接入消息中心應該怎么解決,在不影響老系統增量消息接入消息中心的又不影響歷史消息回調的情況下,消息中心采用了轉發的方式去兼容歷史的消息回調。下面是飛書回調流程:
3.4.2 如何支持飛書通道動態內容消息,消息中心如何去做更友好的兼容適配?
動態消息內容 和 靜態消息內容 指的是消息(如郵件、短信、通知等)中的內容。
靜態消息內容是指在發送消息時事先準備好的、不會發生變化的消息內容,比如營銷郵件、歡迎短信、通知公告等。這些內容在每次發送時都是一樣的,不會根據接收者的情況、時間等因素而發生變化。
而動態消息內容則會根據接收者的情況、時間等因素而實時生成,以提供更好的個性化服務。動態消息內容的例子包括訂單確認郵件、賬戶余額提醒短信、預約成功通知等。這些消息內容需要根據接收者的訂單信息、賬戶信息、預約信息等動態生成。
總之,靜態消息內容是在發送消息前準備好的、不會發生變化的消息內容,而動態消息內容是根據接收者的情況、時間等因素而實時生成的消息內容,以提供更好的個性化服務。
目前跟業務系統對接的消息內容,99%都屬于靜態消息內容,相對于那種較復雜的動態消息內容(圖一折線圖,圖二動態表單等動態數據)去做動態數據渲染。消息中心對于動態內容消息渲染,解決方案是在模板功能里面抽象了一層消息內容解析引擎,模板引擎采用的是Apache 軟件基金會下的一個開源 Java 模板引擎框架(VelocityEngine)該引擎用于生成 HTML、XML、JSON、CSV 等文件格式的文本內容。功能非常強大,感興趣的同學可以去了解一下。下面拿個簡單動態消息模板舉例:
a. API接口組裝消息體
{
"reachType": 2,
"templateCode": "*******",
"sendTime": 1687163457335,
"reachList": [
{
"contentParamList": [
{
"key": "addCourseCount", // 動態參數[新增課程總數 (30)]
"value": "30"
},
{
"key": "lastWeekNewCourseCount", // 動態參數[上周上新課程數量 (20)]
"value": "20"
},
{
"key": "dataList", // 動態參數,數據格式用戶可自定義
"value": "[{\"courseName\":\"測試課程內容1\",\"courseUrl\":\"https://t1-iwork-rdc.shizhuang-inc.net/rdc/desk\"},{\"courseName\":\"測試課程內容2\",\"courseUrl\":\"https://t1-iwork-rdc.shizhuang-inc.net/rdc/desk\"}] "
}
],
"receiverId": "*******"
}
]
}
b. 使用VelocityEngine語法解析
<code>
#set($myList=$dataList) // api接口傳過來的參數
#set($result = '')
#foreach($item in $myList) // 拼接消息內容
#set($result = $result+'['+$item.courseName+']'+'('+$item.courseUrl+')'+'\n')
#end
#set($growthCnotallow="**新人成長(10)**\n$result") // 輸出最終消息內容
</code>
c. 動態渲染輸出
3.4.3 在消息中心平臺推送大規模消息,如何去跟業務系統的機器人去做平衡而不觸發飛書平臺限流
業務場景:在一個陽光明媚的早上,業務同學用潮人研習社的機器人給公司用戶推送了chatgpt的學習先關的內容,消息推送觸達竟然花費了一個1多小時。
問題分析:沒辦法,做為技術boy,只能埋頭去尋找根因,主要有以下幾點
- 如上圖所示,每次消息推送都要做獲取token這個動作,顯然獲取token這個動作是可以優化的?;陲w書返回的失效時間做近端緩存。
- 消息推送接口雖啟用了異步推送,但是在一個消息體里面有很多觸達用戶時,沒有進行分組,底層推送給飛書時還是串行在推消息(這里沒有采用飛書的批量發消息接口,是因為在產品側有個功能要去統計單個用戶已讀未讀的數據,用批量推送的話,具體到用戶粒度的已讀未讀數據飛書是不支持的。另外一個原因就是飛書的機器人不是集中在消息中心進行消息推送,需要考慮飛書側對某個機器人消息推送做限流的問題,一旦使用了某個業務系統的機器人進行批量或并發推送,可能會導致業務系統業務消息推送(限流)異常)。
優化思路:
針對上面2個問題的具體分析,主要是對問題2做了對應的優化,優化思路主要是分治思想,針對大批量推送消息場景對用戶進行分組,充分利用操作系統的多核優勢。把分組的任務提交到異步消息隊列,通過自產自消的方式來提升消息觸達效率。
結果:
基于上面的思路去優化并測試,效果是異常的明顯,之前推送消息需花費1個多小時,現在10分鐘(這里的觸達時效瓶頸主要是飛書側,飛書對消息推送接口做了限流(1s并發只能50且1min上限1000))就可以全部觸達了。
4、總結
4.1 學會聆聽
當完成整個消息中心的設計后,要聽取他人意見,學會聆聽,因為完成這件事其實并不難。另外在網上也可以找到很多開源產品可借鑒,但是完全拿來主義不一定適合我們自己業務。所以需要跟PM、同事討論,聽取意見。再者消息中心未來是需要長期與其它部門及產品協調溝通的,如果一開始在做的時候就沒有與其他人去交流或技術方案討論,那么后期由于業務拓展,很有可能整體架構很容易被推翻重構。
4.2 結語
對于消息中心來說,根據實際業務線的豐富度,相應應用場景也會更加復雜,所以我們在設計消息的落地場景時,對于不同場景的適用性挑戰也會增大。但殊途同歸,基于降本增效去做更多思考,總歸會讓價值落地。