閑魚(yú)策略中樞業(yè)務(wù)擴(kuò)展模塊實(shí)現(xiàn)
2022-11-13|14:42|發(fā)布在分類(lèi) / 開(kāi)網(wǎng)店| 閱讀:84
擴(kuò)展能力是我們?cè)谧銎脚_(tái)、中臺(tái)時(shí)都會(huì)面臨的技術(shù)思考。為了平臺(tái)能盡可能覆蓋更多的業(yè)務(wù)場(chǎng)景,我們需要設(shè)計(jì)可擴(kuò)展,可復(fù)用的擴(kuò)展模塊,不斷拓寬平臺(tái)能力的邊界。本文介紹閑魚(yú)策略中樞平臺(tái)Luxury做業(yè)務(wù)擴(kuò)展模塊時(shí)遇到的問(wèn)題以及解決思路,希望能為同樣做平臺(tái)擴(kuò)展模塊的讀者提供一些啟發(fā)。
背景
閑魚(yú)策略中樞Luxury是面向閑魚(yú)全域業(yè)務(wù)的用戶(hù)精細(xì)化策略運(yùn)營(yíng)平臺(tái),旨在引導(dǎo)用戶(hù)認(rèn)識(shí)、參與閑魚(yú)的各業(yè)務(wù)場(chǎng)景、精準(zhǔn)的傳遞平臺(tái)價(jià)值。
以下面的紅包投放為例,它就是Luxury的一條投放策略投放到客戶(hù)端上之后的展現(xiàn)形式。
一條投放策略包含了:
- 規(guī)則(策略觸發(fā)時(shí)機(jī))。對(duì)應(yīng)紅包例子,觸發(fā)時(shí)機(jī)就是用戶(hù)打開(kāi)客戶(hù)端首頁(yè)時(shí)識(shí)別有未使用紅包
- 觸點(diǎn)(投放的素材樣式)。對(duì)應(yīng)紅包例子,素材樣式就是整個(gè)Pop大卡片樣式
- 鉤子(填充觸點(diǎn)的動(dòng)態(tài)數(shù)據(jù))。對(duì)應(yīng)紅包例子,鉤子就負(fù)責(zé)填充pop卡片中的紅包金額,和標(biāo)題文案
其中,鉤子的定位是負(fù)責(zé)對(duì)接二三方的接口與服務(wù),為素材投放提供動(dòng)態(tài)數(shù)據(jù)。
現(xiàn)狀
- 因?yàn)槎椒?wù)接口格式都不同,做統(tǒng)一和抽象很困難。早期Luxury為了支撐業(yè)務(wù)快速上線(xiàn),二三方服務(wù)接入都是用hard code的形式,case by case的解決。這種方式帶來(lái)的影響有:不僅不能支撐快速迭代的業(yè)務(wù)需求,并且已有服務(wù)也不能沉淀提供給其他策略復(fù)用。
- 鉤子到觸點(diǎn)的映射需要運(yùn)營(yíng)同學(xué)手動(dòng)填寫(xiě)解析表達(dá)式,如下圖所示。需要運(yùn)營(yíng)同學(xué)理解后端的返回?cái)?shù)據(jù)格式,配置成本高且容易配錯(cuò)。
目標(biāo)
- 具備易用性:對(duì)運(yùn)營(yíng)來(lái)說(shuō)不感知鉤子的底層差異,能夠快速完成鉤子到觸點(diǎn)的數(shù)據(jù)映射
- 可擴(kuò)展:能夠覆蓋大部分的業(yè)務(wù)接入場(chǎng)景
- 可復(fù)用:能夠?qū)︺^子進(jìn)行一定程度抽象,避免每次業(yè)務(wù)接入都要開(kāi)發(fā)新勾子
- 可沉淀:鉤子沉淀為可復(fù)用資產(chǎn),逐漸拓寬平臺(tái)能力邊界
技術(shù)方案
鉤子模塊的總體思路是采用適配器模式,抽象出鉤子接口層,二三方服務(wù)可以通過(guò)實(shí)現(xiàn)接口來(lái)接入Luxury平臺(tái)。
適配器模式是可擴(kuò)展性的經(jīng)典解決方案。例如:
- 云原生監(jiān)控系統(tǒng)Prometheus的exporter用來(lái)解決各種異構(gòu)數(shù)據(jù)源metrics上報(bào)的問(wèn)題
- 服務(wù)網(wǎng)格ServiceMesh的Mixer用來(lái)解決每次http調(diào)用時(shí)注入額外的業(yè)務(wù)邏輯
適配器模式做統(tǒng)一抽象的解決方案一般是對(duì)出入?yún)⒆鰯?shù)據(jù)映射,適配到統(tǒng)一的接口模型,對(duì)上層屏蔽底層實(shí)現(xiàn)差異。
鉤子模塊架構(gòu)圖:
鉤子模塊鏈路圖:
入?yún)?gòu)造
- 問(wèn)題:鉤子是策略鏈路上獨(dú)立可復(fù)用的模塊,因此鉤子不與某個(gè)具體策略耦合,也不與某個(gè)具體的客戶(hù)端調(diào)用耦合。這意味著客戶(hù)端的每次調(diào)用不知道要傳哪些參數(shù)給鉤子。
- 解決方案:該類(lèi)問(wèn)題的常規(guī)解決思路是把入?yún)⒌慕Y(jié)構(gòu)信息傳遞到調(diào)用方,讓調(diào)用方感知每次調(diào)用的入?yún)⒏袷?。但這意味著需要拆分成兩次調(diào)用,一次獲取入?yún)⒔Y(jié)構(gòu),一次發(fā)起調(diào)用。但在我們?cè)跈M向分析了自己的業(yè)務(wù)場(chǎng)景,發(fā)現(xiàn)策略的入?yún)⑼蔷?jiǎn),有限,可枚舉的,比如用戶(hù)id、商品id、頁(yè)面id等等。因此我們轉(zhuǎn)變方案,通過(guò)每次調(diào)用時(shí)客戶(hù)端傳遞盡可能全的上下文,而鉤子從調(diào)用上下文里取需要的字段。通過(guò)冗余的參數(shù)換取更簡(jiǎn)單的設(shè)計(jì),更少的調(diào)用次數(shù)。
靜態(tài)配置可視化
- 問(wèn)題:運(yùn)營(yíng)需要在后臺(tái)配置鉤子的靜態(tài)配置,但問(wèn)題是每個(gè)鉤子的靜態(tài)配置結(jié)構(gòu)都不一樣,服務(wù)端的靜態(tài)配置結(jié)構(gòu)需要透?jìng)鞯胶笈_(tái)生成表單讓運(yùn)營(yíng)感知并且理解。傳統(tǒng)解決前后端參數(shù)傳遞的方式是前后端約定接口協(xié)議并且開(kāi)發(fā)頁(yè)面表單,但這種方式對(duì)鉤子不太適用。每次變更都涉及到前后端聯(lián)調(diào),發(fā)布,不能滿(mǎn)足鉤子敏捷擴(kuò)展的需求。
- 解決方案:要解決表單多變且可持續(xù)拓展的問(wèn)題,用schema動(dòng)態(tài)生成表單是一個(gè)好的解決方案。該方案需要前后端約定schema協(xié)議,前端提供schema生成表單的引擎,后端提供類(lèi)生成schema的工具。這樣后端的類(lèi)能直接映射為前端的表單樣式,前端表單的一份配置就對(duì)應(yīng)一個(gè)后端類(lèi)實(shí)例。整個(gè)開(kāi)發(fā)流程能大幅度縮短,支撐鉤子敏捷迭代。
一份生成的表單與對(duì)應(yīng)的schema例子如下:
{"type": "object","properties": {"appId": {"type": "integer","title": "app id","required": true},"callSource": {"type": "string","default": "fleamarket","title": "call source","required": true},"tppParam": {"type": "array","items": {"type": "object","properties": {"key": {"type": "string","title": "tpp入?yún)?,"required": true},"value": {"type": "string","default": "${input.}","description": "支持從input或config從動(dòng)態(tài)獲取參數(shù)","title": "解析表達(dá)式","required": true}}},"description": "從input或config中根據(jù)mvel表達(dá)式獲取參數(shù),最后組裝為kv結(jié)構(gòu)的tppParam","title": "tpp請(qǐng)求param"}}}
出參標(biāo)準(zhǔn)化
- 問(wèn)題:鉤子作為業(yè)務(wù)擴(kuò)展模塊,出參結(jié)構(gòu)是不可窮舉的,難以約束和進(jìn)一步抽象。但矛盾在于如果不做統(tǒng)一的抽象,就會(huì)把出參的復(fù)雜度暴露給外部,外部就需要感知鉤子各種case下的數(shù)據(jù)結(jié)構(gòu),如何對(duì)出參做統(tǒng)一與抽象,屏蔽出參的復(fù)雜性?
- 分析:我們配置觸點(diǎn)與數(shù)據(jù)的映射時(shí)。觸點(diǎn)用一個(gè)一個(gè)占位符挖出來(lái)動(dòng)態(tài)數(shù)據(jù)的“坑”,“坑”是有限且是單一層級(jí)的,不會(huì)出現(xiàn)一個(gè)“坑”里填了個(gè)大對(duì)象或者大列表的場(chǎng)景。
- 解決方案:制定規(guī)范,要求將鉤子的出參映射為平鋪的結(jié)構(gòu),每份平鋪的出參都是一份字典(KVKV結(jié)構(gòu)),每個(gè)KV語(yǔ)義清晰,運(yùn)營(yíng)同學(xué)配置策略時(shí),從字典里挑選需要的動(dòng)態(tài)數(shù)據(jù)字段填入觸點(diǎn),“將有限的數(shù)據(jù)填入有限的坑”。平鋪經(jīng)驗(yàn)證是滿(mǎn)足擴(kuò)展性需求的,就算是嵌套的List結(jié)構(gòu),例如K[0:[0,1], 1:[0,1]]也能平鋪為K_0_0,K_0_1,K_1_0,K_1_1這種結(jié)構(gòu)。
一個(gè)通過(guò)字典配置觸點(diǎn)的例子如下:
數(shù)據(jù)映射可配置化
問(wèn)題:在做紅包權(quán)益鉤子的時(shí)候,我們發(fā)現(xiàn)紅包權(quán)益鉤子的可復(fù)用性不強(qiáng),因?yàn)樗鼉H是TPP算法中臺(tái)上的一種業(yè)務(wù)場(chǎng)景,我們一旦需要接TPP算法中臺(tái)的另一個(gè)算法業(yè)務(wù)場(chǎng)景,就需要重新擴(kuò)展實(shí)現(xiàn)一遍鉤子。
分析:可復(fù)用性不強(qiáng)的原因在于對(duì)接中臺(tái)類(lèi)鉤子時(shí),中臺(tái)本身有很強(qiáng)的拓展能力,而我們的出入?yún)⒌臄?shù)據(jù)映射針對(duì)中臺(tái)上的一種業(yè)務(wù)場(chǎng)景寫(xiě)死的,導(dǎo)致不能復(fù)用到中臺(tái)上的其他業(yè)務(wù)場(chǎng)景。因此,我們需要做到數(shù)據(jù)映射的可配置化。
解決方案:當(dāng)發(fā)現(xiàn)數(shù)據(jù)映射成為擴(kuò)展性的瓶頸時(shí),就要著手解決數(shù)據(jù)映射靈活性的問(wèn)題。因此需要實(shí)現(xiàn)數(shù)據(jù)映射的可配置化,鉤子實(shí)現(xiàn)可配置的數(shù)據(jù)映射引擎,將入?yún)⒊鰠⒌臄?shù)據(jù)映射配置關(guān)系抽出放到靜態(tài)參數(shù)里。這樣中臺(tái)鉤子就不與任意一個(gè)場(chǎng)景耦合,變更場(chǎng)景時(shí)只需要修改數(shù)據(jù)映射配置,不需要重新開(kāi)發(fā)。當(dāng)鉤子實(shí)現(xiàn)不與具體場(chǎng)景耦合時(shí),也就實(shí)現(xiàn)了最大化靈活性。
效果
- 運(yùn)營(yíng)同學(xué)可以獨(dú)立配置鉤子到觸點(diǎn)的映射關(guān)系,鉤子成為了可以靈活替換的數(shù)據(jù)字典,可以按需挑選自己需要的動(dòng)態(tài)數(shù)據(jù)。
- 沉淀了常見(jiàn)中臺(tái)鉤子,能夠覆蓋大部分場(chǎng)景需求,服務(wù)接入僅需0.5day配置成本。
- 覆蓋促買(mǎi)入、促發(fā)布、促瀏覽、活動(dòng)互動(dòng)等多個(gè)業(yè)務(wù)場(chǎng)景。
總結(jié)
擴(kuò)展模塊的設(shè)計(jì)都很“難”,難的原因在于為了保證可擴(kuò)展性,在方案設(shè)計(jì)階段就不能預(yù)設(shè)接入服務(wù)的結(jié)構(gòu)。接入服務(wù)可以是任意一個(gè)接口,任意一個(gè)服務(wù)。對(duì)于這樣沒(méi)有邊界的服務(wù)要做統(tǒng)一和抽象是很困難的。
關(guān)鍵的地方在于統(tǒng)一接口層的定義,也是“規(guī)范”和“協(xié)議“定義。需要我們從業(yè)務(wù)特點(diǎn)出發(fā),在保證可擴(kuò)展性的前提下,保證接口層的語(yǔ)義清晰,在可擴(kuò)展性和易用性之間找到最佳的平衡點(diǎn)。
這個(gè)問(wèn)題還有疑問(wèn)的話(huà),可以加幕.思.城火星老師免費(fèi)咨詢(xún),微.信號(hào)是為: msc496。
難題沒(méi)解決?加我微信給你講!【僅限淘寶賣(mài)家交流運(yùn)營(yíng)知識(shí),非賣(mài)家不要加我哈】>
推薦閱讀:
淘寶生意參謀有沒(méi)有免費(fèi)破解版軟件?生意參謀越獄版在哪里下載?
為什么淘寶買(mǎi)家好評(píng)不顯示?淘寶買(mǎi)家好評(píng)多久顯示出來(lái)?
關(guān)閉自選計(jì)劃多久生效?自選計(jì)劃使用指南
更多資訊請(qǐng)關(guān)注幕 思 城。
別默默看了 登錄\ 注冊(cè) 一起參與討論!