得物增長兌換商城的架構演進
一、簡介
二、誕生背景
三、業(yè)務架構
1. 業(yè)務架構圖
2. 業(yè)務架構概述
四、玩法迭代
1. 整體玩法總覽
2. RPC調(diào)用迭代
3. 庫存設計迭代
4. 獎品橫向迭代
5. 兌換防刷迭代
6. 項目穩(wěn)定性建設
五、更多拓展
1. 抽獎組件搭建器
2. 引入增長的任務中臺
3. 打造簡易的積分系統(tǒng)
六、總結(jié)
一、簡介
在移動互聯(lián)網(wǎng)蓬勃發(fā)展的今天,用戶的選擇日益多元化,App市場的競爭也愈發(fā)白熱化。為了在激烈的市場競爭中脫穎而出,提升用戶獲取效率并增強用戶粘性,越來越多的應用開始采用積分兌換、抽獎等互動玩法。這些精心設計的運營策略不僅能夠滿足用戶的參與感和成就感需求,更能有效促進社交傳播,提升品牌忠誠度。通過持續(xù)優(yōu)化和迭代,開發(fā)者能夠在競爭激烈的市場中占據(jù)優(yōu)勢地位,實現(xiàn)用戶的可持續(xù)增長和長期留存。
基于提升系統(tǒng)復用性和穩(wěn)定性的考量,我們構建了一個統(tǒng)一的兌換商城中臺系統(tǒng)。該中臺旨在為各上游業(yè)務線提供標準化的積分兌換和獎勵機制,使各類應用和服務能夠快速接入并享受便捷的服務支持。通過這一中臺架構,我們不僅實現(xiàn)了核心業(yè)務邏輯的集中化管理與維護,更為后續(xù)的功能擴展(如抽獎、彩票等多樣化玩法)奠定了堅實基礎,從而顯著提升了開發(fā)效率和用戶體驗。
二、誕生背景
在用戶增長和留存策略的探索中,增長團隊先后推出了多種互動類玩法,如每日簽到、星愿森林、心愿海洋以及早期的點鞋成金等。這些玩法通過積分或虛擬貨幣的積累,不僅增強了用戶的參與感,也為用戶提供了豐富的獎勵機制。然而,隨著玩法的多樣化,如何高效管理這些積分或貨幣的消耗途徑,成為提升用戶體驗和趣味性的關鍵。
每日簽到
星愿森林
心愿海洋
點鞋成金
兌換專區(qū)
兌換專區(qū)
兌換專區(qū)
兌換專區(qū)
面對這一挑戰(zhàn),團隊意識到為每個互動玩法單獨開發(fā)兌換功能不僅需要前后端的全面支持,還需重復搭建復雜的監(jiān)控和預警系統(tǒng)以防范潛在的資損風險。這種重復開發(fā)的模式不僅成本高昂,而且難以保證系統(tǒng)的一致性和穩(wěn)定性。因此,構建一個統(tǒng)一的積分商城,為各互動玩法提供通用化的兌換系統(tǒng),成為了提升開發(fā)效率和確保系統(tǒng)安全性的必然選擇。這樣不僅優(yōu)化了資源配置,也為后續(xù)的玩法擴展和用戶體驗升級奠定了堅實的基礎。
在既有兌換業(yè)務的基礎上,我們也成功沉淀并提煉了多個核心領域模型。后續(xù)基于這些通用化的領域模型,我們逐步探索并實現(xiàn)了多種新型玩法的快速落地,包括老虎機、盲盒以及抽獎券等多樣化互動形式。
三、業(yè)務架構業(yè)務
架構圖
圖片
業(yè)務架構概述
業(yè)務架構主要分4級:
- 上層業(yè)務? 主要是有使用兌換商城功能的上游應用,包括星愿森林、每日簽到、心愿海洋、增長新客、社區(qū)抽獎、學生答題等應用。
- 玩法沉淀? 主要包括三類玩法,包括積分兌換、老虎機/盲盒,以及抽獎券等。玩法核心所依賴的領域模型基本相似,各個系統(tǒng)都能得到了很好的復用。而在玩法層面,我們主要使用了設計模式中的模板模式,優(yōu)先搭建好每個玩法的骨架,然后將一些關鍵步驟交由上游應用自定義實現(xiàn)。
- 領域模型? 活動:對應每個新接入的應用都需要新建一個活動模型,而各類自定義的業(yè)務層面的邏輯都是在活動維度上實現(xiàn)的。? 模板:模板作為上下關系的重要承接,一個活動能夠創(chuàng)建多個模板,而每個模板下又可以關聯(lián)多個獎品。之所以存在模板這個中間層,是有多個原因的。 ? 原因1:模板和活動之間的關系,我們可以以星愿森林為例,一個活動他是存在多個兌換專區(qū)的,包含了合種專區(qū)、超值專區(qū)等,這些是需要通過模板維度來劃分的。 ? 原因2:模板和獎品之間的關系,獎品需要關聯(lián)到不同的資產(chǎn),創(chuàng)建一個獎品的成本較高。而將獎品設計成可以被綁定到多個模板上,獎品這個資產(chǎn)就可以得到一個很好的復用。同時每個模板中該獎品有其獨立的庫存模塊,那么模板之間就不會互相影響了。 ? ...? 獎品:后臺不同類型的獎品統(tǒng)一都需要在獎品庫內(nèi)創(chuàng)建。這樣我們就能在不同的活動和模板中在獎品庫內(nèi)選出該獎品。每次新增新的類型獎品,需要實現(xiàn)該新類型獎品的發(fā)獎能力,如優(yōu)惠券、津貼、現(xiàn)金等都依賴不同的下游應用進行發(fā)放。? 庫存:目前支持分時間段庫存、每日庫存以及總庫存邏輯頻控,包含用戶及獎品的發(fā)放頻控、包含每日頻次、周期循環(huán)頻次以及總頻次。
- 下游依賴? 主要是兌換商城所依賴的下游應用,包括營銷中臺、商品聚合中心、提現(xiàn)中臺、口令服務、增長配置中心等。
四、玩法迭代
整體玩法總覽
本次玩法迭代的介紹主要以積分兌換玩法為主,參考樣式如下:
圖片
要想兌換具體的商品需要經(jīng)過一系列流程,下圖為兌換的主流程介紹,包含了用戶從發(fā)起兌換到最終兌換成功或失敗的流程。主要為用戶選擇某個獎品兌換需要處理的一系列業(yè)務邏輯。
如上文所說,在玩法層面,主要使用了設計模式中的模板模式,利用自己領域模型的能力,優(yōu)先搭建好兌換玩法的骨架,比如有效性校驗、庫存扣減、獎品發(fā)放等邏輯,然后將一些關鍵步驟如前置自定義檢查、扣減貨幣、回滾操作交由上游應用自定義實現(xiàn)。
玩法內(nèi)置邏輯是由商城內(nèi)部的領域模型實現(xiàn),主要包含通用邏輯如下:
- 各個模型的有效性校驗:確保兌換請求的合法性。
- 庫存及頻控模型的前置校驗:檢查庫存和頻控模型,確保兌換請求的可行性。
- 庫存扣減邏輯:扣減獎品庫存,確保庫存數(shù)據(jù)的實時性和準確性。
- 獎勵模型的發(fā)放邏輯:發(fā)放用戶所兌換的獎品。
- 兌換成功后置處理:進行兌換成功的后置處理,如記錄日志、更新用戶狀態(tài)等。
即下圖灰色模塊是由商城自己的玩法模板實現(xiàn)。
需業(yè)務方對接邏輯主要包含:
- 前置自定義校驗:實現(xiàn)特定業(yè)務規(guī)則的前置校驗。
- 貨幣扣減:扣除用戶相應的積分或虛擬貨幣。
- 兌換失敗后的貨幣回滾:在兌換失敗時,將扣除的積分或虛擬貨幣返還給用戶。
即黃色箭頭及模塊是由商城側(cè)發(fā)起,調(diào)用上游接入應用,由上游應用處理相關邏輯,然后通知商城成功與否。
圖片
RPC調(diào)用迭代
1.0版本
在最初的版本中,黃色模塊(如前置自定義檢查、扣減貨幣、回滾操作)的實現(xiàn)方式較為繁瑣。具體流程如下:
- 上游業(yè)務方提供protobuf文件:每個新接入的業(yè)務方需要提供自己的protobuf文件。
- 生成go-grpc的server及client端樁代碼:根據(jù)protobuf文件生成go-grpc的server和client端樁代碼。
- 商城服務編寫代碼調(diào)用client端樁代碼:在商城服務中編寫代碼,調(diào)用client端樁代碼發(fā)起RPC調(diào)用。
這種實現(xiàn)方式存在以下問題:
- 開發(fā)成本高:每次新接入一個業(yè)務,都需要在商城服務和接入方同時編寫代碼。
- 維護復雜:隨著業(yè)務接入數(shù)量的增加,代碼維護和管理的復雜度顯著提升。
圖片
2.0版本
為了減少商城側(cè)的開發(fā)成本,我們借鑒了Java的SPI(Service Provider Interface)概念,對RPC調(diào)用進行了優(yōu)化。具體實現(xiàn)如下:
- 商城統(tǒng)一生成protobuf的server端代碼:商城統(tǒng)一生成protobuf的server端代碼,作為服務提供者接口。
- 活動模塊統(tǒng)一配置調(diào)用路由:在商城服務的活動模塊中,統(tǒng)一配置調(diào)用路由,實現(xiàn)服務的動態(tài)路由和調(diào)用。
- 接入方引用protobuf生成的server端樁代碼:每次有新業(yè)務接入,接入方只需引用對應protobuf生成的server端樁代碼,并通過反向注冊機制實現(xiàn)服務的注冊和調(diào)用。
這種實現(xiàn)方式帶來了以下優(yōu)勢:
- 開發(fā)成本降低 :商城層無需再為每個新接入的業(yè)務編寫代碼,只需進行應用配置。
- 維護簡化 :通過統(tǒng)一的服務提供者接口和調(diào)用路由,代碼維護和管理的復雜度顯著降低。
- 擴展性強 :新業(yè)務的接入更加便捷,系統(tǒng)的擴展性和靈活性得到提升。
通過這種優(yōu)化,我們不僅實現(xiàn)了RPC調(diào)用的高效復用,還為未來的業(yè)務擴展和系統(tǒng)優(yōu)化奠定了堅實的基礎。這種模塊化、可配置的設計理念,不僅提升了開發(fā)效率,還增強了系統(tǒng)的靈活性和可擴展性。
圖片
庫存設計迭代
一開始庫存只有每日及總庫存的概念,實現(xiàn)也比較簡單。為了保障庫存扣減的并發(fā)安全,使用Redis作為庫存的存儲。具體的庫存扣減則通過提前設置好Redis值并不斷扣減即可。由于Redis的單線程特性,也不用擔心并發(fā)重復扣減的風險。Redis一直扣減直至數(shù)值小于0就表示庫存已被耗盡。
rest, err := redis.decr(key)
if err {
...
return err
}
if rest < 0 {
return limitErr
}
而后需求迭代中出現(xiàn)了分時間段庫存,每天需要分成多個時段來分配庫存,每個時間段的庫存如果未被耗盡會累積到下一個時段。這個時候通過簡單的Decr命令就不能滿足需求了。
- 方案一 :為每個時段單獨設置一個Redis的key,但這樣會導致某個時段的庫存被浪費,不符合功能需求。要實現(xiàn)庫存累積效果,需要在進入下一個時段時將上一個時段的庫存加到下一個時段,增加了實現(xiàn)復雜度。
- 方案二 :繼續(xù)使用同一個庫存key,但需要拆分成兩次Redis命令調(diào)用,首先判斷當前時段的庫存是否足夠,然后進行扣減庫存。這種非事務性的執(zhí)行方式可能導致并發(fā)問題,難以確保庫存被準確扣減。
考慮到實現(xiàn)成本,我們選擇了方案二。具體邏輯如下:
圖片
- 當前剩余未釋放庫存 = 總庫存 - 當前已釋放庫存(即timeStock)? 當前已釋放庫存是當前已過時段各個庫存的累加。
- 如果當前庫存 < 當前剩余未釋放庫存,表示當前時段已無可使用庫存,返回-1。
- 否則,返回當前剩余未釋放庫存-1。
圖片
為了解決并發(fā)問題,我們引入了Lua腳本,確保庫存扣減的原子性。
LUA腳本偽代碼:
# KEYS[1] 為 redis的key
# ARGV[1] 為 提前算出的剩余未釋放庫存
# return的值 < 0 代表庫存扣減失敗
local _args1 = ARGV[1]
local stock = redis.call('GET', KEYS[1])
if stock < _args1 then
return -1
else
local rest = redis.call('DECR', KEYS[1])
return rest
end
return -1
獎品橫向迭代
圖片
商城內(nèi)部的獎品都統(tǒng)一維護在獎品庫里,每個類型的獎品都有通用屬性和擴展屬性,同時不同的獎品背后對應著不同的資產(chǎn),需要有獨立的發(fā)獎邏輯(資產(chǎn)發(fā)放)。因此每增加一個類型的獎品,不僅需要增加獎品類型的枚舉,也需要對接下游資產(chǎn)的發(fā)放功能。
商城從一開始便不斷的在新增不同類型的獎品,從優(yōu)惠券、代金券、津貼,到后面拓展出現(xiàn)金、虛擬獎品、道具等獎品。
而一些特殊的獎品,比如抽獎券,單獨實現(xiàn)一個發(fā)獎邏輯就不能實現(xiàn)一個完整功能,為此我們還特地拓展出抽獎券玩法。具體玩法是:用戶需要在開獎前獲得抽獎券,這時會發(fā)放一個抽獎碼給用戶,我們會在指定時間根據(jù)規(guī)則進行開獎并通知獲獎的用戶。這里除了發(fā)放抽獎券的邏輯之外,我們還需要一個獨立的開獎功能。
開獎流程如下圖:
圖片
抽獎券的玩法迭代:
抽獎券玩法的核心在于開獎定時任務的邏輯,這類抽獎券活動不同于獎品兌換,單次活動可能有百萬人參與,一萬人中獎的情況。那么這樣開獎Job的實時計算量就過于龐大了,測試環(huán)境按照這個量級進行開獎的話,耗時就已達到10多分鐘之久。這個時長對于開獎腳本來說是不可接受的了,不僅用戶體驗達不到預期,而且時長太長,這段時間如果服務一旦出現(xiàn)其他情況(如新功能部署、容器節(jié)點被調(diào)度等)中斷開獎流程更是會阻塞流程。
為此我們做了以下迭代優(yōu)化:
- 開獎Job的實時計算前置:在用戶兌換抽獎券時,系統(tǒng)提前為用戶打好標簽,并隨機計算出一個分數(shù)。將用戶的分數(shù)加入到Redis的有序隊列中。這樣,在開獎時只需從有序隊列中取數(shù),大大減少了實時計算量。
- 開獎Job引入并發(fā)操作:允許多場次和多獎品同時進行匹配,顯著提高開獎效率。當然,為了避免并發(fā)操作引起的數(shù)據(jù)錯亂,在關鍵流程中加入了Mutex鎖,確保數(shù)據(jù)的一致性和完整性。
- 異常通知與一鍵重開功能:在應用出現(xiàn)各類意外情況導致開獎流程被阻塞時,我們會有異常通知告知負責人,并提供一鍵重開的功能。
最終效果:經(jīng)過以上優(yōu)化,正式版上線時,100萬人的開獎時長從10多分鐘縮短了30倍,僅需20秒即可完成開獎。這不僅大幅提升了用戶體驗,還增強了系統(tǒng)的穩(wěn)定性和可靠性。
兌換防刷迭代
針對于防刷策略,項目從最開始只是通過接口驗簽及H5參數(shù)加密進行防控,但這種方式的破解成本比較低,也很容易被黑灰產(chǎn)刷接口。到后面我們便系統(tǒng)梳理了從業(yè)務層、接口層及黑灰產(chǎn)防控三方面對代碼進行加固。
- 業(yè)務層防刷? 首先是獎品維度的頻控,這是基于3.2-業(yè)務架構概述中模板模型實現(xiàn)的,包含每日頻次、周期循環(huán)頻次以及總頻次。? 其次是活動維度的頻控,這個是在兌換流程中,商城中臺給業(yè)務方提供了開放能力。在兌換前置環(huán)節(jié)可以自定義校驗邏輯,比如N天可兌換N次。
圖片
圖片
- 接口層防刷? 這個主要是依賴于得物統(tǒng)一的流控中心,可以針對于單個接口配置限流和熔斷策略,這里就不過多贅述了。
- 黑灰產(chǎn)防控? 針對于這部分流量,我們首先是通過接口驗簽和時間校驗先過濾一部分。? 其次是針對IP及設備的黑名單過濾。? 還有就是針對于高價值獎品,我們會在前置環(huán)節(jié)預埋token,只有通過正常流程的用戶才能進行兌換。
項目穩(wěn)定性建設
商城作為一個潛在的資損高危區(qū),在穩(wěn)定性建設上投入大量資源是必要的。本文我們首先聚焦于問題發(fā)現(xiàn)及應急止血方面的工作,包括通過監(jiān)控和告警快速發(fā)現(xiàn)問題,以及通過一鍵止損開關及時對發(fā)生異常的業(yè)務進行熔斷。
監(jiān)控告警
在監(jiān)控告警方面,我們采用了多種技術手段來確保系統(tǒng)的穩(wěn)定性和及時發(fā)現(xiàn)潛在問題:
業(yè)務監(jiān)控組件:對于一些明細數(shù)據(jù)的同環(huán)比對比,我們使用了得物通用的業(yè)務監(jiān)控組件。這種組件能夠?qū)崟r監(jiān)控業(yè)務數(shù)據(jù)的變化,幫助我們快速發(fā)現(xiàn)異常情況。
Prometheus SDK埋點:對于一些需要分位數(shù)統(tǒng)計的數(shù)據(jù),我們使用了Golang的Prometheus SDK進行埋點,并統(tǒng)一收集上報。
最終這些數(shù)據(jù)統(tǒng)一接入到增長的監(jiān)控大盤中,能夠清晰地看到各個接入方實時的訪問數(shù)據(jù)、兌換數(shù)量及面額等。
告警配置:根據(jù)采集到的數(shù)據(jù),我們根據(jù)規(guī)則指標制作了各類告警通知,確保在異常情況發(fā)生時能夠及時響應:
- 事前預警 :獎品庫存的實時通知與查看,確保庫存充足。
- 事中告警 :獎品數(shù)量及金額的同環(huán)比變化,及時發(fā)現(xiàn)異常波動。
- 事后統(tǒng)計 :獎品的核銷率及T+1天金額對賬,確保數(shù)據(jù)準確無誤。
圖片
圖片
圖片
|
|
一鍵止損開關
為了在發(fā)生異常時能夠快速響應,我們引入了一鍵止損開關。這個開關能夠在檢測到異常情況時,立即對相關業(yè)務進行熔斷,防止資損進一步擴大。通過這種機制,我們能夠在最短時間內(nèi)控制問題,減少損失。
五、更多拓展
抽獎組件搭建器
為了進一步提升抽獎玩法的易用性和靈活性,我們與前端團隊聯(lián)合打造了可視化的H5抽獎組件。該組件基于商城中臺,提供了完整的抽獎解決方案,運營人員只需按照SOP文檔進行配置,即可快速接入抽獎玩法并投入使用,真正實現(xiàn)了抽獎玩法的“開箱即用”。
產(chǎn)品特性:
- 開箱即用: 提供完整的前后端組件, 支持九宮格/翻拍/老虎機等樣式;
- 中獎控制: 中獎次數(shù)及中獎頻次控制;
- 庫存控制: 獎品每日/總庫存控制, 分時段釋放;
- 多種獎品: 優(yōu)惠券/代金券/津貼/虛擬獎品等;
部分組件樣式如下,也支持在可視化的H5搭建器內(nèi)自定義組件樣式。
圖片
在抽獎組件的設計中,抽獎次數(shù)的獲取是一個關鍵環(huán)節(jié)。最初,這一功能完全依賴于業(yè)務方自行實現(xiàn),這導致只有已經(jīng)接入過商城玩法的業(yè)務方才能使用H5的抽獎組件。為了提升組件的通用性和易用性,我們進行了以下優(yōu)化:
引入增長的任務中臺
為了簡化抽獎次數(shù)的獲取流程,我們引入了增長的任務中臺。通過這一中臺,用戶可以完成配置的指定任務來獲得積分,這些積分可以直接用于參與抽獎。
圖片
打造簡易的積分系統(tǒng)
我們打造了一個完整的積分系統(tǒng),實現(xiàn)了從獲得積分、消耗積分到領取獎勵的閉環(huán)流程。具體實現(xiàn)如下:
- 獲得積分:用戶通過完成指定任務(任務中臺提供了非常豐富的任務類型)獲得積分。
- 消耗積分:用戶使用積分參與抽獎,系統(tǒng)自動扣除相應積分。
- 領取獎勵:用戶中獎后,系統(tǒng)自動發(fā)放獎品,完成整個抽獎流程。
這種閉環(huán)流程的設計帶來了多重優(yōu)勢:
- 簡化接入流程 :業(yè)務方無需自行實現(xiàn)抽獎次數(shù)的獲取邏輯,降低了接入成本。
- 增強通用性 :所有業(yè)務方都可以通過積分系統(tǒng)使用H5抽獎組件,提升了組件的適用范圍。
六、總結(jié)
本文講述了增長兌換商城整體的業(yè)務框架及部分功能的實現(xiàn)細節(jié)。兌換商城作為一個中臺,承接了不同上下游提出的需求,很多功能的實現(xiàn)都需要考慮到通用性及拓展性,而一些復雜需求或功能的實現(xiàn),是否會加重配置的難度,影響后續(xù)業(yè)務方的接入成本,都是需要在項目迭代中不斷思考的問題。不僅如此,在迭代過程中的穩(wěn)定性保障也會是商城自始至終的基本要求。
對于兌換商城之后的規(guī)劃:
- 拓展玩法:引入更潮流、更具吸引力的玩法,以保持用戶的持續(xù)參與和新鮮感。通過不斷創(chuàng)新,確保商城始終處于用戶增長的前沿。
- 降本提效:輸出簡版玩法及后臺配置,維護每個版本的Changelog及SOP文檔,確保迭代過程透明且可追溯。精簡業(yè)務接入流程,減少開發(fā)成本和維護成本,提升整體效率。
- 交流進步:本文作為大綱綜述,簡要的講解了兌換商城整體的架構,后續(xù)將輸出更深入的博客文章,詳細探討兌換商城的核心技術實現(xiàn)、優(yōu)化策略。通過不斷的技術交流,促進項目的成熟和優(yōu)化,確保商城系統(tǒng)的高效穩(wěn)定運行。