NBF事件中心架构设计与实现
簡(jiǎn)介:NBF是阿里巴巴供應(yīng)鏈中臺(tái)的基礎(chǔ)技術(shù)團(tuán)隊(duì)打造的一個(gè)技術(shù)PaaS平臺(tái),她提供了微服務(wù)FaaS框架,低代碼平臺(tái)和中臺(tái)基礎(chǔ)設(shè)施等一系列的PaaS產(chǎn)品,旨在幫助業(yè)務(wù)伙伴快速?gòu)?fù)用和擴(kuò)展中臺(tái)能力,提升研發(fā)效能和對(duì)外的商業(yè)化輸出。事件中心就是NBF系列技術(shù)產(chǎn)品中的一員。本文首先介紹事件驅(qū)動(dòng)架構(gòu)的概念及適用場(chǎng)景,然后會(huì)介紹事件中心產(chǎn)品的設(shè)計(jì)和實(shí)現(xiàn)。
作者 | 林暉
來(lái)源 | 阿里技術(shù)公眾號(hào)
一 業(yè)務(wù)背景
電商平臺(tái)供應(yīng)鏈的業(yè)務(wù)場(chǎng)景非常復(fù)雜,技術(shù)中臺(tái)需要支持非常復(fù)雜且不斷變化的業(yè)務(wù)需求,構(gòu)建了數(shù)量繁多且緊密耦合的業(yè)務(wù)鏈路,為技術(shù)架構(gòu)的維護(hù)帶來(lái)了壓力。
1 問(wèn)題描述
上圖是一個(gè)典型的業(yè)務(wù)架構(gòu),A域是上游域,B域和C域是下游域。A域在收到外部調(diào)用請(qǐng)求時(shí),首先同步調(diào)用B域的服務(wù)接口完成同步業(yè)務(wù)邏輯,然后發(fā)送消息通知到MQ。C域異步消費(fèi)消息后,反向調(diào)用A域的接口查詢?cè)敿?xì)信息,完成異步業(yè)務(wù)邏輯。
這種架構(gòu)的問(wèn)題包括:
面對(duì)這些問(wèn)題,我們希望應(yīng)用事件驅(qū)動(dòng)架構(gòu)的特性來(lái)解耦子域,降低業(yè)務(wù)鏈路復(fù)雜度,構(gòu)建穩(wěn)定并向前兼容的事件契約,從而提升全域的穩(wěn)定性。
2 事件驅(qū)動(dòng)架構(gòu)的應(yīng)用過(guò)程
3 關(guān)于NBF
NBF[1] 是阿里巴巴供應(yīng)鏈中臺(tái)的基礎(chǔ)技術(shù)團(tuán)隊(duì)打造的一個(gè)技術(shù)PaaS平臺(tái),全稱是New-Retail Business Factory,她提供了微服務(wù)FaaS框架,低代碼平臺(tái)和中臺(tái)基礎(chǔ)設(shè)施等一系列的PaaS產(chǎn)品,旨在幫助業(yè)務(wù)伙伴快速?gòu)?fù)用和擴(kuò)展中臺(tái)能力,提升研發(fā)效能和對(duì)外的商業(yè)化輸出。事件中心就是NBF系列技術(shù)產(chǎn)品中的一員。
本文首先介紹事件驅(qū)動(dòng)架構(gòu)的概念及適用場(chǎng)景,然后會(huì)介紹事件中心產(chǎn)品的設(shè)計(jì)和實(shí)現(xiàn)。
二 什么是事件驅(qū)動(dòng)架構(gòu)(EDA)
1 領(lǐng)域事件
很多同學(xué)會(huì)將事件和消息混淆。在業(yè)務(wù)系統(tǒng)中,事件指的是領(lǐng)域事件,而消息可以是任意數(shù)據(jù)或數(shù)據(jù)片段。領(lǐng)域事件的特點(diǎn)包括:
2 事件驅(qū)動(dòng)架構(gòu)的概念
和很多架構(gòu)名詞類似,事件驅(qū)動(dòng)架構(gòu)并沒(méi)有一個(gè)明確的定義和能力范圍。Martin Fowler在2017年的文章[2] 中描述了與事件驅(qū)動(dòng)架構(gòu)相關(guān)的一些主要模式。在本文中,事件驅(qū)動(dòng)架構(gòu)的概念具象為由領(lǐng)域事件驅(qū)動(dòng)的業(yè)務(wù)流技術(shù)架構(gòu)。每一個(gè)領(lǐng)域事件都對(duì)應(yīng)一個(gè)業(yè)務(wù)流中的具體活動(dòng)(如采購(gòu)單建單),而事件就是活動(dòng)發(fā)生導(dǎo)致的結(jié)果(如采購(gòu)單建單完成事件),事件內(nèi)容就是活動(dòng)導(dǎo)致的完整狀態(tài)變化(如采購(gòu)單+子單列表)。
3 事件驅(qū)動(dòng)架構(gòu)的優(yōu)點(diǎn)
在Fundamentals of Software Architecture[3] 以及Microservices Patterns[4]等書中描述了事件驅(qū)動(dòng)架構(gòu)的一些明顯特點(diǎn),我們總結(jié)為以下幾項(xiàng):
4 事件驅(qū)動(dòng)架構(gòu)能解決什么實(shí)際問(wèn)題
下面我們舉幾個(gè)例子來(lái)描述事件驅(qū)動(dòng)架構(gòu)的解耦和廣播能力如何幫助解決現(xiàn)實(shí)工作中的問(wèn)題:
解耦能力
在基于請(qǐng)求/響應(yīng)方式的服務(wù)化架構(gòu)中,上游服務(wù)按照約定的RPC接口調(diào)用下游服務(wù),這樣有一個(gè)比較嚴(yán)重的問(wèn)題:上游服務(wù)作為數(shù)據(jù)(例如業(yè)務(wù)單據(jù))的生產(chǎn)者,強(qiáng)依賴了作為數(shù)據(jù)消費(fèi)方的下游服務(wù)所定義的接口,導(dǎo)致上游服務(wù)自身無(wú)法沉淀接口和數(shù)據(jù)標(biāo)準(zhǔn)。
一種更合理的方案是依賴倒置:由上游服務(wù)定義SPI,下游服務(wù)實(shí)現(xiàn)SPI,這樣,上游服務(wù)終于有機(jī)會(huì)沉淀出自身的接口和數(shù)據(jù)標(biāo)準(zhǔn),不再需要適配各個(gè)下游服務(wù)的接口,而是由下游服務(wù)的開發(fā)者按照接口文檔來(lái)做實(shí)現(xiàn)。但這種設(shè)計(jì)仍然無(wú)法解決運(yùn)行時(shí)上游服務(wù)仍然依賴下游服務(wù)的問(wèn)題,下游服務(wù)的可用性、一致性、冪等性能力會(huì)直接影響上游服務(wù)的相關(guān)指標(biāo)及實(shí)現(xiàn)方式,需要上下游服務(wù)開發(fā)者一起對(duì)齊方案,在出問(wèn)題時(shí)一起解決。
使用事件驅(qū)動(dòng)設(shè)計(jì)可以實(shí)現(xiàn)契約定義和運(yùn)行時(shí)的全面解耦:上游服務(wù)可以沉淀自己的事件契約,在運(yùn)行時(shí)無(wú)論是上游服務(wù)還是下游服務(wù)都只依賴事件Broker,下游服務(wù)的可用性和一致性等問(wèn)題由事件Broker來(lái)保障。
廣播能力
在供應(yīng)鏈中臺(tái)這樣復(fù)雜的微服務(wù)架構(gòu)中,關(guān)鍵的上游服務(wù)往往有多個(gè)下游服務(wù),上游服務(wù)一般需要順序或并發(fā)調(diào)用所有的下游服務(wù)來(lái)完成一次完整的調(diào)用。
上游服務(wù)的開發(fā)者會(huì)面臨多個(gè)難題:
而下游服務(wù)的開發(fā)者也有自己的問(wèn)題:
使用事件驅(qū)動(dòng)架構(gòu)天然可以避免上述問(wèn)題:
5 事件驅(qū)動(dòng)架構(gòu)不適合什么場(chǎng)景
三 事件中心的功能設(shè)計(jì)
作為面向中臺(tái)的事件中間件,事件中心集成了消息中間件MetaQ(RocketMQ),初始使用體感也與MQ很像,但事件中心有很多不同的功能設(shè)計(jì):
四 事件中心的運(yùn)行時(shí)架構(gòu)
事件中心運(yùn)行態(tài)主要由以下部分組成:
1、事件中心服務(wù)/SDK
a) SDK:包含事件收發(fā)的主要邏輯,支持事務(wù)發(fā)送和普通發(fā)送,支持事件校驗(yàn)、壓縮、本地備份;
b) Tunnel Service:一層很薄的數(shù)據(jù)庫(kù)代理服務(wù),支持按應(yīng)用、事件、場(chǎng)景、IO維度的限流,支持?jǐn)?shù)據(jù)庫(kù)快速靈活擴(kuò)容;
c) Index Service:事件索引服務(wù),通過(guò)精衛(wèi)(DataX)獲取Binlog,解析為索引后寫入索引表(Lindorm)。
2、阿里中間件
a) Diamond(Nacos):包含應(yīng)用相關(guān)的全部配置信息,如發(fā)送、訂閱關(guān)系、事件定義、中間件配置等;
b) SchedulerX:調(diào)度SDK執(zhí)行事件重新發(fā)送、重新消費(fèi)、事務(wù)異常狀態(tài)問(wèn)詢;
c) MetaQ:主要的事件收發(fā)管道;
d) TDDL(RDS):事件內(nèi)容及消費(fèi)記錄存儲(chǔ);
e) 精衛(wèi):用于生成索引、計(jì)算延遲等異步處理邏輯;
f) Lindrom(serverless):用于存放事件外部索引,serverless模式支持按量付費(fèi)和彈性擴(kuò)容,性能比較穩(wěn)定。
下圖為簡(jiǎn)化的運(yùn)行時(shí)架構(gòu)圖,圖中藍(lán)色線條表示事件的正常收發(fā)鏈路(事務(wù)發(fā)送),紅色線條表示事件的異常處理鏈路。
1 事件發(fā)送與消費(fèi)流程
事件結(jié)構(gòu)
運(yùn)行時(shí)的一條事件實(shí)例由三部分組成:
1、事件ID:全局唯一,格式為“邏輯庫(kù)編號(hào)_月內(nèi)發(fā)送日期_uuid”,例如01_11_f75ec4fb347c49c4bc3e93xxxxxxxx,其中邏輯庫(kù)編號(hào)用于邏輯庫(kù)路由,日期用于事件清理;
2、事件Head:包含事件元信息,如trace信息、發(fā)送者信息、事件大小、MetaQ信息等,參考示例:
3、事件Body:JSON格式,包含由用戶已定義的事件內(nèi)容,事件內(nèi)容要符合事件定義契約,否則會(huì)被拒絕發(fā)送。
運(yùn)行時(shí)的事件可能有多個(gè)消費(fèi)方,每個(gè)消費(fèi)方會(huì)產(chǎn)生一條消費(fèi)記錄,消費(fèi)記錄包含:
- 事件ID
- 消費(fèi)信息:消費(fèi)狀態(tài)、消費(fèi)次數(shù)、下次消費(fèi)時(shí)間等
事件發(fā)送流程
事件中心支持事務(wù)發(fā)送和非事務(wù)發(fā)送兩種模式,使用狀態(tài)機(jī)驅(qū)動(dòng),API設(shè)計(jì)與MetaQ的API基本一致。以下以事務(wù)發(fā)送為例介紹發(fā)送流程,由于非事務(wù)發(fā)送的流程更簡(jiǎn)單,所以不再詳細(xì)介紹。
1)事務(wù)發(fā)送狀態(tài)機(jī)
2)事務(wù)發(fā)送時(shí)序圖
3)異常狀態(tài)事務(wù)問(wèn)詢
事件消費(fèi)流程
事件消費(fèi)流程也使用狀態(tài)機(jī)驅(qū)動(dòng),API相比MetaQ有一些不同:
1)事件消費(fèi)狀態(tài)機(jī)
2)重試周期
事件進(jìn)入消費(fèi)失敗狀態(tài)后,事件中心會(huì)周期調(diào)用用戶Listener重新消費(fèi),消費(fèi)周期以5s起始指數(shù)增加,最多重試15次,最大為5 * 214 = 81920秒(約22小時(shí))。
3)事件消費(fèi)時(shí)序圖
2 事件存儲(chǔ)
數(shù)據(jù)表
事件中心使用了32分庫(kù)的TDDL,按照HASH(事件ID)做分庫(kù),每個(gè)庫(kù)上有以下幾張表:
事件生命周期
3 外部索引
事件發(fā)送歷史列表、事件索引查詢和事件重投是事件中心運(yùn)維平臺(tái)的主要功能。其中索引查詢功能的查詢速度快、查詢結(jié)果準(zhǔn)確,用戶反饋一直比較好。
索引配置
用戶在修改事件定義時(shí),可以為其中任意基礎(chǔ)類型字段配置為“查詢字段”,事件中心會(huì)在運(yùn)行時(shí)解析該字段的值,并創(chuàng)建索引;一個(gè)事件中的每個(gè)查詢字段都會(huì)對(duì)應(yīng)一條索引;即使沒(méi)有配置查詢字段,也會(huì)生成一條包含時(shí)間戳的索引,用于已發(fā)送事件的排序和分頁(yè)。
索引結(jié)構(gòu)
事件中心的索引為KV結(jié)構(gòu),使用Lindorm的寬表存儲(chǔ),按使用場(chǎng)景分為兩種類型:
其中
查詢性能
通過(guò)目前事件中心運(yùn)維平臺(tái)99%的查詢都可以在毫秒級(jí)別返回結(jié)果,Lindorm索引行數(shù)在十億級(jí)別。
五 總結(jié)
本文介紹了事件驅(qū)動(dòng)架構(gòu)在供應(yīng)鏈執(zhí)行鏈路的應(yīng)用背景和實(shí)踐過(guò)程,并介紹了NBF事件中心產(chǎn)品的設(shè)計(jì)和部分實(shí)現(xiàn)。目前事件中心每日事件發(fā)送量峰值在千萬(wàn)級(jí)別,平穩(wěn)度過(guò)了雙11、雙12、年貨節(jié)等流量高峰。
原文鏈接
本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。?
總結(jié)
以上是生活随笔為你收集整理的NBF事件中心架构设计与实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2022,你的团队距离持续部署还有多远?
- 下一篇: 使用 Flink Hudi 构建流式数据