自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

嗶哩嗶哩直播通用獎勵系統(tǒng)揭秘

開發(fā) 架構(gòu)
通用獎勵系統(tǒng)的設(shè)計需要從分別從需求側(cè)和供給側(cè)兩個方向入手:一是發(fā)放場景接入,二是獎品類型接入,獎勵系統(tǒng)為二者制訂了接入標(biāo)準(zhǔn),方便進(jìn)行后續(xù)的擴(kuò)展維護(hù)。

背景

B站直播平臺近年來迅猛發(fā)展,為了吸引更多觀眾和優(yōu)質(zhì)主播,直播平臺通常會推出多樣玩法(包括節(jié)日活動、任務(wù)、榜單、抽獎),以激勵用戶參與和創(chuàng)造高質(zhì)量內(nèi)容,拉動平臺營收,豐富直播生態(tài)。諸多玩法都存在一個共同的場景:給用戶發(fā)放獎勵。為了滿足獎品種類以及發(fā)放場景的多樣性,我們設(shè)計了通用獎勵系統(tǒng),用于支撐各類上層業(yè)務(wù)。本文將介紹直播獎勵系統(tǒng)的技術(shù)架構(gòu),從需求分析到實(shí)現(xiàn)細(xì)節(jié),全面解析其背后的技術(shù)方案。

圖片圖片

需求分析

通用獎勵系統(tǒng)的設(shè)計需要從分別從需求側(cè)和供給側(cè)兩個方向入手:一是發(fā)放場景接入,二是獎品類型接入,獎勵系統(tǒng)為二者制訂了接入標(biāo)準(zhǔn),方便進(jìn)行后續(xù)的擴(kuò)展維護(hù)。

圖片圖片

從業(yè)務(wù)接入來看,獎勵系統(tǒng)需要滿足各類上游場景的發(fā)放,如:榜單截榜后發(fā)獎、任務(wù)完成發(fā)獎、抽獎發(fā)獎、競猜開獎發(fā)獎等諸多場景,因此接入方式既要足夠標(biāo)準(zhǔn)化又要兼容差異化。

從獎品類型來看,獎勵存在多樣性,既包含頭像框、頭銜、房間皮膚等權(quán)益類獎品,又包含電池、金倉鼠、包裹道具等價值類獎品,不同的獎品各自所需的配置屬性不同,由不同的下游發(fā)放,且每個下游吞吐能力也不一致,獎勵系統(tǒng)在處理獎勵發(fā)放時需要分別設(shè)置不同的發(fā)放限流閾值以防止擊垮下游。

從發(fā)放時效來看,業(yè)務(wù)能級有高低之分,高能級的業(yè)務(wù)場景發(fā)放延遲會造成用戶體驗(yàn)下降,甚至?xí)l(fā)客訴輿情,因此需要有獨(dú)立的發(fā)放通道專門用于保障高優(yōu)業(yè)務(wù)。

最后作為一個值得被信任的獎勵系統(tǒng),一定要滿足這三個特點(diǎn):低延遲、不超發(fā)、不漏發(fā)。

架構(gòu)介紹

基于獎勵上游業(yè)務(wù)方多、峰值流量高、穩(wěn)定性要求高的特點(diǎn),為求高峰值流量下獎勵系統(tǒng)的穩(wěn)定可靠,方案選型時選擇了基于消息隊(duì)列削峰、異步處理請求的總體方案。以下是獎勵系統(tǒng)整體架構(gòu)圖:

圖片圖片

系統(tǒng)架構(gòu)包括:

  • 接入層:負(fù)責(zé)制定業(yè)務(wù)接入標(biāo)準(zhǔn),提供業(yè)務(wù)源注冊、獎勵發(fā)放、回收、獎品佩戴、取消佩戴等功能;
  • 配置層:按照業(yè)務(wù)所需配置各類獎勵包裹,如:排行榜發(fā)獎、主播任務(wù)發(fā)獎、獎池抽獎發(fā)獎,同時還負(fù)責(zé)新獎勵類型的配置接入;
  • 服務(wù)層:處理接入層的獎勵請求,拆分包裹,記錄發(fā)放狀態(tài),管理發(fā)獎二級隊(duì)列,調(diào)度不同的獎品下游進(jìn)行獎勵發(fā)放;
  • 存儲層:架構(gòu)中依賴的存儲方案
  • databus 作為MQ提升吞吐量
  • mysql負(fù)責(zé)存儲基本配置、獎品和包裹的映射關(guān)系以及發(fā)放記錄
  • taishanKV存儲獎品擴(kuò)展配置
  • redis 負(fù)責(zé)提供二級隊(duì)列、延遲重試隊(duì)列
  • hdfs 存儲獎勵配置和發(fā)放記錄離線數(shù)據(jù),提供分析、篩查等功能
  • 離線層:數(shù)平oneservice數(shù)據(jù)檢索、掃描異常發(fā)放記錄狀態(tài)補(bǔ)發(fā)獎勵、系統(tǒng)日志、相關(guān)數(shù)據(jù)埋點(diǎn)

詳細(xì)設(shè)計

發(fā)獎流程按照:業(yè)務(wù)上游 → 一級隊(duì)列 → 二級隊(duì)列 → 發(fā)放下游 四個模塊串行,簡單直觀,業(yè)務(wù)方僅需配置獎勵,再調(diào)用接口投遞發(fā)獎消息即可,非常便捷,串行流程如下圖所示:

圖片

針對需求中的三個特點(diǎn)系統(tǒng)分別進(jìn)行了如下設(shè)計:

  • 低延遲:提供不同通道的隔離發(fā)放,針對高優(yōu)業(yè)務(wù)可選擇Fast通道,防止發(fā)放量過大的低優(yōu)業(yè)務(wù)影響高優(yōu)業(yè)務(wù)的發(fā)獎時長;
  • 不超發(fā):獎勵中心設(shè)計了全鏈路冪等,上游消息攜帶 source + msg_id,中間寫庫設(shè)置DB唯一鍵防止重復(fù)消費(fèi),下游提供支持冪等的發(fā)放接口,確保獎勵無論怎么重試都不會被超發(fā);
  • 不漏發(fā):層層重試,因獎勵系統(tǒng)存在多重異步,針對每一步都設(shè)置相應(yīng)的重試策略,避免中途鏈路中斷產(chǎn)生漏發(fā)。

古希臘哲學(xué)家赫拉克利特曾說過:"The only constant is change.",意思就是:唯一不變的是變化。這句話提醒我們要接受變化和不確定性,并在這種情況下保持適應(yīng)能力,設(shè)計系統(tǒng)也是如此,外部的變量太多,不能僅僅停留在理想狀態(tài)思考問題,因此獎勵系統(tǒng)在容錯上做了不少細(xì)節(jié)設(shè)計:

1.快慢隊(duì)列

某天凌晨收到大量客訴,反饋直播獎勵到賬延遲,排查下來是運(yùn)營上了一個用戶觀看直播10min獲得抽獎券的任務(wù),0點(diǎn)10分過后,大量的發(fā)獎消息涌入隊(duì)列,當(dāng)時獎勵系統(tǒng)沒做消息隔離,造成高優(yōu)業(yè)務(wù)的發(fā)獎消息消費(fèi)延遲。

圖片圖片

圖片圖片

直播按業(yè)務(wù)能級可以劃分高優(yōu)和低優(yōu)兩類業(yè)務(wù),一般低優(yōu)類業(yè)務(wù)因門檻較低所以獎勵發(fā)放量比較大,如:用戶觀看直播獲得抽獎券。而高優(yōu)類業(yè)務(wù)往往獎勵發(fā)放量比較少,如:用戶消費(fèi)電池參與活動獲得獎勵。不同的是這兩類業(yè)務(wù)各自對發(fā)放時效的敏感度,低優(yōu)業(yè)務(wù)對時效不敏感,可接受延遲發(fā)放;高優(yōu)業(yè)務(wù)時效敏感,獎勵延遲到賬易導(dǎo)致用戶體驗(yàn)降低,甚至帶來客訴。

獎勵系統(tǒng)提供了讓業(yè)務(wù)自主選擇快慢通道的能力,上游可根據(jù)業(yè)務(wù)是否容忍延遲來選擇快慢通道,可滿足不同場景下的業(yè)務(wù)需求。

2.冪等

一級消息處理器接到消息后首先獲取獎勵包裹子獎勵,如果這一步出現(xiàn)異常,會直接返回消息重試信號,等待消費(fèi)者重試。

接著將包裹中包含的所有獎勵進(jìn)行封裝,再按 uid%64 進(jìn)行分庫寫表,這里會通過DB組合唯一鍵 souce + msgId + awardTypeId + awardId + uid 實(shí)現(xiàn)發(fā)獎冪等判斷,如果已經(jīng)存在發(fā)獎記錄則跳過本次寫入,之后再根據(jù)快慢隊(duì)列各自的發(fā)獎鏈路進(jìn)行二級隊(duì)列轉(zhuǎn)投,防止因某個下游發(fā)獎處理過慢導(dǎo)致整體消費(fèi)吞吐量下滑造成的消息積壓。

慢通道消息會按照獎品類型進(jìn)行隊(duì)列分配,一種獎品類型分到一組redis list隊(duì)列,具體隊(duì)列key的數(shù)量由初始化配置決定,而快隊(duì)列則是選擇databus,直接分成三個不同等級隊(duì)列,這么選擇的原因主要有以下兩點(diǎn):

  • 快通道對獎勵可達(dá)性和時效性要求較高,因此選用高可用的MQ作為承載方式,但使用MQ需要單獨(dú)申請producer和consumer,這在運(yùn)維部署上面增加了成本,因此只申請了高、中、低三個二級隊(duì)列,避免了每次新增獎品類型都需要單獨(dú)部署資源,針對不同的獎品類型會按照配置進(jìn)行隊(duì)列分配,比如涉及金錢的獎品類型會放入Fast隊(duì)列,優(yōu)先保障;一些已知的慢下游會主動配置放到Slow隊(duì)列,避免拖慢整個發(fā)放隊(duì)列,其他的獎品類型默認(rèn)進(jìn)入Default隊(duì)列;
  • 慢通道對獎勵的時效性要求較低,redis list 不會增加運(yùn)維負(fù)擔(dān),對于應(yīng)用來說只是從邏輯上劃分了多個隊(duì)列,非常便于擴(kuò)充新獎品類型,但redis的可用性比起MQ稍顯不足,一旦出現(xiàn)意外情況可能會丟失數(shù)據(jù),因此需要有離線補(bǔ)償?shù)氖侄?,但這會犧牲獎勵發(fā)放的時效性,因此僅針對慢通道的獎勵采用這種模式。

3.可重試

二級隊(duì)列消費(fèi)者隨時監(jiān)聽二級隊(duì)列消息,收到發(fā)獎消息后根據(jù)不同的獎品類型進(jìn)行下游發(fā)放交互,拿到結(jié)果后更新DB狀態(tài)(如果失敗則會累計重試發(fā)放次數(shù)),更新產(chǎn)生的binlog會被canal監(jiān)聽,如果遇到發(fā)放異常需要重試的情況會將消息寫入三級隊(duì)列,此隊(duì)列主要用于獎勵重試,基于 redis zset 結(jié)構(gòu)設(shè)計的延遲隊(duì)列進(jìn)行指數(shù)退避重試發(fā)獎,按照 2^0s → 2^1s → 2^2s → ... → 2^12s,自動重試13次,大概在2小時左右,如果還未恢復(fù),則判定為下游不可用,不再重試發(fā)獎等待人工介入。

圖片圖片

4.離線補(bǔ)償

只要發(fā)獎記錄落表成功,無論如何都需要走到最終的發(fā)獎,因此我們專門為此設(shè)計了離線補(bǔ)償方案,通過job定時撈取離線庫未發(fā)放完成的狀態(tài)記錄進(jìn)行重試發(fā)放,如此可保證在最壞情況下的兜底,最大程度保證獎勵的可達(dá)性。

5.業(yè)務(wù)接入

為了降低上游接入成本,獎勵中心設(shè)計了一套易于理解且接入簡單的消息格式,同時支持面向未來擴(kuò)展,消息格式如下:

MQ消息體
{
    "source":"(int64)業(yè)務(wù)來源,由獎勵中心頒發(fā)",
    "msg_id":"(string)消息id,同一個投遞來源下的消息id需要保證唯一",
    "uids":"([]int64)發(fā)獎勵的目標(biāo)uid,支持單條消息給多人發(fā)獎",
    "package_id":"(string)獎勵包裹ID,內(nèi)部封裝了多個子獎勵",
    "msg_time":"(int64)業(yè)務(wù)方時間戳,默認(rèn)不傳用下游接收到的時間處理",
    "extra_data":"(string)擴(kuò)展字段,json格式,用于面向擴(kuò)展",
    "business_type":"(string)業(yè)務(wù)類型,統(tǒng)計使用",
    "business_id":"(string)業(yè)務(wù)ID,統(tǒng)計使用",
    "expire_time":"(int64)動態(tài)過期時間戳,此時間會覆蓋package內(nèi)配置的過期時間"
}
  
extra_data 格式:
{
    "lottery":{
        "count":"(int64)發(fā)放包裹數(shù)量,在已有包裹獎勵配置的數(shù)量上再*count得到最終發(fā)放數(shù)量"
    },
    "send_gold_seeds_package":{
        "room_id":"(int64)送出的直播間id",
        "ruid":"(int64)送出的主播ID"
    }
}

以上消息基本滿足語義:給xx用戶發(fā)放xx獎勵,易于理解,消息體內(nèi)已經(jīng)約定了冪等鍵,按照 source + msg_id 組成聯(lián)合冪等鍵,防止超發(fā),此外還支持了 extra_data 用于針對一些特定場景,比如動態(tài)數(shù)量、動態(tài)直播間等場景,如果未來有擴(kuò)展需求可基于此持續(xù)迭代。

6.獎勵配置

上面的發(fā)放條件內(nèi)包含package_id,代指獎勵包裹,其內(nèi)部封裝了我們發(fā)獎所需要的所有獎品參數(shù),通過可視化面板進(jìn)行獎品配置:

圖片圖片

獎品配置主要分為4個部分:

  • 包裹ID :通過編輯不同的編號產(chǎn)生不一樣的包裹ID,如果想把多個獎品放入同一個包裹可以給它們設(shè)置相同的編號;
  • 基本屬性:選擇獎勵類型,再根據(jù)類型對應(yīng)的屬性分別配置獎勵I(lǐng)D、數(shù)量、有效期,不同的類型屬性不同,取決于服務(wù)端下發(fā);
  • 擴(kuò)展屬性:不同的獎品類型附帶的發(fā)獎參數(shù)也不相同,擴(kuò)展屬性根據(jù)獎勵類型進(jìn)行附加,以便在發(fā)放時作為參數(shù)攜帶;
  • 顯示配置:用于C端展示;

針對上述結(jié)構(gòu),我們抽象出獎勵的基本結(jié)構(gòu)體如下:

// AwardType 獎品類型
type AwardType struct {
    // 類型ID
    TypeId int64 `json:"type_id"`
    // 類型名
    TypeName string `json:"type_name"`
    // 對C端展示類型名(為空則展示 TypeName)
    ShowTypeName string `json:"show_type_name"`
    // 類型值(用于標(biāo)記擴(kuò)展字段)
    TypeVal string `json:"type_val"`
    // 獎勵I(lǐng)D控件類型 none:無 select:下拉 input:輸入
    AwardIdControl string `json:"award_id_control"`
    // 獎品是否存在數(shù)量配置 0:否 1:是
    IsNum int64 `json:"is_num"`
    // 是否存在有效期配置 0:否 1:是
    IsTime int64 `json:"is_time"`
    // 有效期配置
    TimeConfigData []*AwardTypeTime `json:"time_config_data"`
    // 擴(kuò)展屬性控件配置
    ExtendPropControl []*ExtendPropControlItem `json:"extend_prop_control"`
}
  
// SelectItem 擴(kuò)展屬性下拉數(shù)據(jù)選項(xiàng)
type SelectItem struct {
    Id   string `json:"id"`
    Name string `json:"name"`
}
  
// ExtendPropControlItem 擴(kuò)展屬性
type ExtendPropControlItem struct {
    // 屬性名
    PropName string `json:"prop_name"`
    // 顯示表頭名
    ColumnName string `json:"column_name"`
    // 控件類型 switch、input、select
    PropControl string `json:"prop_control"`
    // 控件下拉數(shù)據(jù),僅限控件類型為 select 會用到
    PropSelectData []*SelectItem `json:"prop_select_data"`
}
  
// AwardTypeTime 獎品有效期配置
type AwardTypeTime struct {
    // 有效期類型id
    TimeType int64 `json:"time_type"`
    // 有效期類型說明
    TimeTypeDesc string `json:"time_type_desc"`
    // 有效期值控件 (none:無 datepicker:日期選擇框 input:文本框)
    TimeValControl string `json:"time_val_control"`
    // 有效期單位控件 (none:無 select:下拉框)
    TimeUnitControl string `json:"time_unit_control"`
    // 有效期單位數(shù)據(jù)
    TimeUnitData []*SelectItem `json:"time_unit_data"`
}

服務(wù)端可以通過接口告知配置后臺應(yīng)該如何渲染配置面板,從而在新增獎品類型的時候無需后臺介入開發(fā),提升生產(chǎn)效率。

7.新獎品類型接入

作為一個通用的獎勵系統(tǒng),快捷高效地接入新的獎品類型應(yīng)該放在首要位置考慮,系統(tǒng)設(shè)計了標(biāo)準(zhǔn)的獎勵發(fā)放和回收接口,用于實(shí)現(xiàn)快速接入新類型能力,如圖所示:

圖片圖片

AwardTypeFunc為獎勵接口,AwardTypeDefaultFunc 為默認(rèn)實(shí)現(xiàn),下面繼承自AwardTypeDefaultFunc的各個struct為具體獎勵,在這里真正實(shí)現(xiàn)下游接口的調(diào)用。

獎勵發(fā)放接口拿到上游獎勵包裹配置數(shù)據(jù)和發(fā)放消息參數(shù)后,先進(jìn)行參數(shù)驗(yàn)證,計算獎勵的過期時間,調(diào)用下游接口進(jìn)行獎勵發(fā)放,由于下游接口實(shí)現(xiàn)標(biāo)準(zhǔn)各不統(tǒng)一,如不支持批量用戶發(fā)放,還需要獎勵自身做一層適配轉(zhuǎn)換,最終給到上游結(jié)果,結(jié)果返回發(fā)放成功的用戶ID、發(fā)放失敗的用戶ID、需要重試的用戶ID以及失敗的具體錯誤明細(xì),上游再根據(jù)返回值做對應(yīng)的流程操作。

8.數(shù)據(jù)監(jiān)控

系統(tǒng)目前做了獎勵發(fā)放記錄相關(guān)的埋點(diǎn),可以觀測到一段時間范圍內(nèi)各個獎品類型的發(fā)放情況,通過監(jiān)控可分析出單品斜率過高的獎勵,從而針對治理(提速、隔離、限速)。

圖片圖片

未來規(guī)劃

獎勵系統(tǒng)經(jīng)過多次迭代逐步演化成如今的多層次架構(gòu),未來還需要在以下幾個方向分別進(jìn)行建設(shè):

  1. 獎勵配置復(fù)雜度過高導(dǎo)致配置準(zhǔn)確性無法保障,需要接入配置自檢能力,盡早檢測出配置問題,避免線上事故;
  2. 系統(tǒng)的監(jiān)控粒度覆蓋不夠全面,如:獎勵發(fā)放異常監(jiān)控、上游發(fā)放來源監(jiān)控、各個隊(duì)列的生產(chǎn)消費(fèi)情況監(jiān)控;
  3. 測試環(huán)境自動化回歸。
責(zé)任編輯:武曉燕 來源: 嗶哩嗶哩技術(shù)
相關(guān)推薦

2019-04-24 09:48:54

2022-12-13 07:32:46

2023-07-04 07:11:30

數(shù)據(jù)分析中臺

2015-10-30 17:48:55

2023-04-26 00:59:49

嗶哩嗶哩工程優(yōu)化

2022-11-30 10:33:03

直播技術(shù)

2021-06-04 14:56:36

App青少年模式未成年人

2022-04-08 14:21:56

App個性化推薦算法推薦管理

2020-04-26 19:57:08

天翼云

2021-08-23 11:15:20

Python機(jī)器學(xué)習(xí)bilibili

2021-08-21 14:30:58

機(jī)器學(xué)習(xí)bilibili股價

2018-02-24 18:11:11

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號