聊聊轉(zhuǎn)轉(zhuǎn)商品到手價(jià)設(shè)計(jì)
一、背景介紹
1.1 問題
- 搜索結(jié)果落地頁,按照價(jià)格篩選及排序,結(jié)果不太準(zhǔn)確;
- 用戶按照價(jià)格篩選后的商品與實(shí)際存在的商品不符,可能會(huì)缺失部分商品,影響到用戶購物體驗(yàn)。
1.2 到手價(jià)模塊在促銷架構(gòu)中所處的位置
在整體架構(gòu)中,商品的到手價(jià)涉及紅包,活動(dòng)等模塊的協(xié)同工作。通過將商品售價(jià)、紅包、活動(dòng)等因素納入綜合考慮,計(jì)算出最終的到手價(jià),為顧客提供良好的購物體驗(yàn)。
二、設(shè)計(jì)目標(biāo)
- 體驗(yàn):用戶及時(shí)看到商品的最新到手價(jià),提升用戶購物體驗(yàn);
- 實(shí)時(shí)性:由原來的半小時(shí)看到商品的最新到手價(jià),提升到3分鐘內(nèi)。
三、技術(shù)方案核心點(diǎn)
3.1 影響因素
影響商品到手價(jià)的主要因素:
- 商品,發(fā)布或改價(jià);
- 紅包,新增/刪除或過期;
- 活動(dòng)/會(huì)館,加入或踢出。
3.2 計(jì)算公式
如圖所示,商品詳情頁到手價(jià)的優(yōu)惠項(xiàng)明細(xì)可用公式總結(jié)如下:
商品的到手價(jià) = 商品原價(jià) - 活動(dòng)促銷金額 - 紅包最大優(yōu)惠金額
四、落地過程及效果
隨著業(yè)務(wù)需求的變化,系統(tǒng)也需要不斷地增加新功能或者對(duì)現(xiàn)有功能進(jìn)行改進(jìn),通過版本演進(jìn),可以逐步引入新的功能模塊或優(yōu)化現(xiàn)有模塊,以滿足業(yè)務(wù)的需求。
商品的到手價(jià)設(shè)計(jì)也是遵循這樣規(guī)則,從開始的v1.0快速開發(fā)上線,響應(yīng)業(yè)務(wù);到v2.0,v3.0進(jìn)行性能優(yōu)化,升級(jí)改造,使用戶體驗(yàn)更佳,更及時(shí)。
4.1 v1.0流程
v1.0流程一共分為兩步:
- 定時(shí)任務(wù)拉取拉取特定業(yè)務(wù)線的全量商品,將這批商品全量推送給各個(gè)接入方;
- 促銷系統(tǒng)提供回查接口,根據(jù)商品id等參數(shù),查詢商品的到手價(jià);
4.2 v1.0任務(wù)及接口
- v1.0任務(wù)執(zhí)行時(shí)間長(zhǎng),偶爾還會(huì)出現(xiàn)執(zhí)行失敗的情況;而在正常情況下用戶大概需要半小時(shí)左右才能感知到最新的商品到手價(jià);
- 需要提供額外的單商品及批量商品接口查詢到手價(jià),無疑會(huì)對(duì)系統(tǒng)產(chǎn)生額外的查詢壓力,隨著接入方的增加,接口qps會(huì)成比例增加;
4.3 v2.0設(shè)計(jì)
針對(duì)v1.0版本長(zhǎng)達(dá)半個(gè)小時(shí)更新一次到手價(jià)問題,v2.0解決方案如下:
- 實(shí)時(shí)處理部分
商品上架/商品改價(jià);
商品加入/踢出活動(dòng);
商品加入/踢出會(huì)館;
這部分?jǐn)?shù)據(jù)的特點(diǎn)是,上述這些操作是能實(shí)時(shí)拿到商品的infoId,基于這些商品的infoId,可以立即計(jì)算這些商品的到手價(jià)并更新出去。
商品發(fā)布/改價(jià),加入活動(dòng)/會(huì)館,踢出活動(dòng)/會(huì)館;接收這些情況下觸發(fā)的mq消息,攜帶商品infoId,直接計(jì)算到手價(jià)。
- 3min任務(wù),計(jì)算特定業(yè)務(wù)線的全量商品到手價(jià)
紅包: 新增/更新/刪除/過期;
這部分?jǐn)?shù)據(jù)的特點(diǎn)是,一是不能很容易能圈出受到影響的這批商品infoIds,二是有些紅包的領(lǐng)取和使用范圍可能會(huì)涉及絕大部分的商品,甚至有些時(shí)候大型促銷會(huì)配置一些全平臺(tái)紅包,影響范圍就是全量商品。
綜上,結(jié)合這兩種情況,以及現(xiàn)有的接口及能力實(shí)現(xiàn)v2.0;
推送商品的到手價(jià),消息體格式如下,包括商品id,平臺(tái)類型,到手價(jià):
[
{"infoId":"16606xxxxxxx174465",
"ptType":"10","
realPrice":"638000"}
]
首先在Redis維護(hù)全量商品,根據(jù)商品上架/下架消息,新增或刪除隊(duì)列中的商品;其次將全量商品保存在10000隊(duì)列中,每個(gè)隊(duì)列只存一部分商品:
queue1=[infoId...]
queue2=[infoId...]
...
queue9999=[infoId...]
右圖顯示的是每個(gè)隊(duì)列存儲(chǔ)的商品數(shù),隊(duì)列商品數(shù)使其能保持在同一個(gè)量級(jí)。
多線程并發(fā)計(jì)算,每個(gè)線程只計(jì)算自己隊(duì)列的商品到手價(jià)即可;同時(shí)增加監(jiān)控及告警,查看每個(gè)線程的計(jì)算耗時(shí),右圖可以看到大概在120s內(nèi)各線程計(jì)算完成。
注意事項(xiàng):
- 避免無意義的計(jì)算: 將每次變化的紅包維護(hù)在一個(gè)隊(duì)列中,任務(wù)執(zhí)行時(shí)判斷是否有紅包更新;
- 并發(fā)問題: 當(dāng)任務(wù)正在執(zhí)行中時(shí),此時(shí)恰巧商品有變化(改價(jià),加入活動(dòng)等),將此次商品放入補(bǔ)償隊(duì)列中,延遲執(zhí)行;
綜上,結(jié)合這兩種場(chǎng)景可以做到:
- 某些場(chǎng)景影響商品的到手價(jià)(如改價(jià)等),攜帶了商品infoId,能做到實(shí)時(shí)計(jì)算并立即推送最新的到手價(jià);
- 拆分多個(gè)商品隊(duì)列,并發(fā)計(jì)算;各司其職,每個(gè)線程只計(jì)算自己隊(duì)列商品的到手價(jià);
- 降低促銷系統(tǒng)壓力,接入方只需要監(jiān)聽到手價(jià)消息即可。
4.4 v3.0設(shè)計(jì)
可以看到隨著商品數(shù)的增加,計(jì)算耗時(shí)也成比例增加。
解決辦法:
- 使用分片,v2.0是將一個(gè)大任務(wù),由jvm多線程并發(fā)執(zhí)行各自隊(duì)列的商品;v3.0則是將這個(gè)大任務(wù),由多個(gè)分片去執(zhí)行各自隊(duì)列中的商品,使其分布式執(zhí)行來提高任務(wù)的執(zhí)行效率和可靠性;
- 擴(kuò)展性及穩(wěn)定性強(qiáng),隨著商品的增多,可以適當(dāng)增加分片數(shù),降低計(jì)算耗時(shí)。
5 總結(jié)
- 系統(tǒng)擴(kuò)展性 數(shù)據(jù)量日漸增大,系統(tǒng)要能做升級(jí)擴(kuò)展;
- 系統(tǒng)穩(wěn)定性 業(yè)務(wù)迭代,架構(gòu)升級(jí),保持系統(tǒng)穩(wěn)定;
- 完備的監(jiān)控告警 及時(shí)的監(jiān)控告警,快速發(fā)現(xiàn)問題,解決問題;
- 演進(jìn)原則 早期不過度設(shè)計(jì),不同時(shí)期采用不同架構(gòu),持續(xù)迭代。