<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          萬級TPS優(yōu)惠券系統(tǒng)設計與實踐

          共 4899字,需瀏覽 10分鐘

           ·

          2024-11-13 08:45


          ??目錄


          1 背景介紹

          2 什么是優(yōu)惠券系統(tǒng)?

          3 優(yōu)惠券創(chuàng)建

          4 優(yōu)惠券派發(fā)

          5 后續(xù)優(yōu)化




          優(yōu)惠券是電商常見的營銷手段,是營銷平臺中的一個重要組成部分,既可以作為促銷活動的載體,也是重要的引流入口。在剛剛過去的電商大促周期內(nèi),各大電商平臺都有配置不同類目、價位的優(yōu)惠券,吸引用戶下單購買。

          優(yōu)惠券系統(tǒng)主要涵蓋四個核心能力:創(chuàng)建、派發(fā)、使用、統(tǒng)計。本篇主要針對派發(fā)這部分,在系統(tǒng)設計和落地過程中遇到和解決的一些問題做一個簡單記錄,以便后來補缺。

          關注騰訊云開發(fā)者,一手技術干貨提前解鎖??





          01



          背景介紹

          優(yōu)惠券是電商常見的營銷手段,是營銷平臺中的一個重要組成部分,騰訊云 MALL 也需要搭建優(yōu)惠券相關的平臺能力來更好的助力賦能商家的各種促銷場景。




          02



          什么是優(yōu)惠券系統(tǒng)?

          這里找了幾個電商平臺的優(yōu)惠券相關頁面:



          依次是某東、某寶、騰訊云 MALL ,這里各式各樣的優(yōu)惠券背后涉及的相關系統(tǒng),可以統(tǒng)稱為優(yōu)惠券系統(tǒng)。所以單說優(yōu)惠券系統(tǒng)是一個很龐大的系統(tǒng),這里收斂一下講其中主要有四大核心能力:創(chuàng)建、派發(fā)、使用、統(tǒng)計。


             2.1 系統(tǒng)架構(gòu)



          本篇主要介紹的是平臺如何創(chuàng)建和派發(fā)優(yōu)惠券到用戶賬戶的券包里,即上面提到的四大核心能力中的創(chuàng)建和派發(fā)。




          03



          優(yōu)惠券創(chuàng)建

             3.1 核心概念


          先簡單了解一下兩個概念:優(yōu)惠券批次、優(yōu)惠券。

          1. 優(yōu)惠券批次:一批相同優(yōu)惠券的生成模版。

          2. 優(yōu)惠券:根據(jù)批次信息生成,優(yōu)惠券與批次的對應關系是 N:1。



             3.2 批次表核心字段


          1. 批次 ID ;

          2. 優(yōu)惠券名稱;

          3. 優(yōu)惠券類型;

          4. 庫存數(shù)量;

          5. 優(yōu)惠規(guī)則如:滿減,滿折等;

          6. 生效規(guī)則:固定生效時間、領取后生效時間等;

          7. 領取規(guī)則:批次每天限領數(shù)量、用戶每天限領數(shù)量、用戶總限領數(shù)量等;

          8. 使用規(guī)則:指定商家、指定商品、指定類目、指定場景等。


             3.3 優(yōu)惠券表核心字段


          1. 優(yōu)惠券 ID:分布式 ID 全局唯一

          2. 批次 ID;

          3. 用戶 ID;

          4. 優(yōu)惠券狀態(tài);

          5. 上下文信息。


          批次表的數(shù)據(jù)寫入主要是 B 端后臺管理來操作,這里不多贅述。


          優(yōu)惠券表數(shù)據(jù)主要通過派發(fā)動作與用戶關聯(lián)后寫入,后面會展開介紹。


             3.4 B 端配置效果





          04



          優(yōu)惠券派發(fā)

             4.1 兩大主要問題


          1. 庫存管理,如何防止超發(fā),保障庫存安全。

          2. 場景復雜,如何支持高并發(fā)及瞬時高流量毛刺場景。


          流量毛刺示意:



             4.2 主流程拆解


          1. 庫存扣減;

          2. 生成優(yōu)惠券。


             4.2.1 庫存扣減


          1. 直接用數(shù)據(jù)庫做庫存管理,面臨問題:高并發(fā)導致數(shù)據(jù)庫崩潰、性能瓶頸明顯。

          2. 緩存做庫存管理:數(shù)據(jù)不一致、穿透、擊穿、雪崩等問題。


          最終方案:


          Redis+Lua+庫存異步分段增補:

          1. Redis+Lua:支持高并發(fā)庫存扣減。

          2. 庫存異步分段增補:支持高并發(fā)的前提下靈活分配庫存。


          Lua 腳本示意(示意代碼僅供學習參考):


          --批次的HashKeylocal stockKey = KEYS[1];
          --Argv 參數(shù)local stockId = ARGV[1];local couponId = ARGV[2];local uid = ARGV[3];--該批次當天最大發(fā)放量local maxByDay = ARGV[4];-- 每人限領local maxByUser = ARGV[5];--當前時間Strlocal crtDateStr = ARGV[6];-- 每人每日限領local dailyMaxByUser = ARGV[7];
          stockId = tonumber(stockId);maxByUser = tonumber(maxByUser);maxByDay = tonumber(maxByDay);dailyMaxByUser = tonumber(dailyMaxByUser);
          --StockKey nilif not stockKey then return '-4'end--Argv nilif not stockId or not couponId or not uid or not maxByUser or not maxByDay or not crtDateStr or not dailyMaxByUser then return '-5'end
          local leftAmountField = 'left_amount';local res = redis.call("HMGET", stockKey, leftAmountField, crtDateStr);local leftAmount = tonumber(res[1]);local crtDispatchAmount = tonumber(res[2]);local couponIdSetKey = stockKey .. ':coupon:zset';
          --優(yōu)惠券ID是否已經(jīng)分配庫存local score = redis.call("ZSCORE", couponIdSetKey, couponId);-- couponId 已經(jīng)存在if score then return '-6';end
          -- 庫存不足if not leftAmount or leftAmount <= 0 then return '-3';end
          --達到當天發(fā)放上限if crtDispatchAmount and crtDispatchAmount >= maxByDay then return '-1';end
          -- 該批次每人每日領取數(shù)量HashKeylocal dailyUserAcquireNumKey = stockKey .. ":user:acquire:" .. crtDateStr;if dailyMaxByUser > 0 then local dailyUserAcquireNum = redis.call("HGET", dailyUserAcquireNumKey, uid); dailyUserAcquireNum = tonumber(dailyUserAcquireNum); -- 達到每人每日領取上限 if dailyUserAcquireNum and dailyUserAcquireNum >= dailyMaxByUser then return '-7' endend
          --該批次用戶領取數(shù)量HashKeylocal userAcquireNumKey = stockKey .. ":user:acquire";local usrAcquireNum = redis.call("HGET", userAcquireNumKey, uid);usrAcquireNum = tonumber(usrAcquireNum);
          --達到用戶領取上限if usrAcquireNum and usrAcquireNum >= maxByUser then return '-2'end
          --扣減庫存-1local leftAmountAfterOp = redis.call("HINCRBY", stockKey, leftAmountField, -1);--當天發(fā)放量+1local crtDispatchAmountAfterOp = redis.call("HINCRBY", stockKey, crtDateStr, 1);--當前用戶發(fā)放量+1local usrAcquireNumAfterOp = redis.call("HINCRBY", userAcquireNumKey, uid, 1);-- 當前用戶當天發(fā)放量+1local dailyUserAcquireNumAfterOp = redis.call("HINCRBY", dailyUserAcquireNumKey, uid, 1);
          redis.call("ZADD", couponIdSetKey, uid, couponId);
          --返回操作之后的上下文,緩存中剩余量,當天已經(jīng)發(fā)放量,用戶已經(jīng)領取量,用戶當天已經(jīng)領取量return '0|' .. leftAmountAfterOp .. '|' .. crtDispatchAmountAfterOp .. '|' .. usrAcquireNumAfterOp .. '|' .. dailyUserAcquireNumAfterOp


          分段增補示意:



          介紹:


          每當 Redis 剩余庫存小于 M 個時,異步從數(shù)據(jù)庫增補 N 個庫存到 Redis 里,保證 Redis 庫存數(shù)量一直小于等于數(shù)據(jù)庫。


          1. 屏蔽流量直接打到數(shù)據(jù)庫,減輕數(shù)據(jù)庫壓力。

          2. Redis+數(shù)據(jù)庫控制,雙重保證不超發(fā)。

          3. 庫存增補的 M 和 N 可以根據(jù)實際業(yè)務需要靈活調(diào)配。

            1. M 可以理解為業(yè)務發(fā)券速率兜底。比如:發(fā)快補慢提示無庫存等。

            2. N 可以理解為極端情況下最大允許丟失的庫存數(shù)量。


          主流程如圖:



             4.2.2 生成優(yōu)惠劵


          1. 扣減庫存成功同步生成優(yōu)惠券信息寫入數(shù)據(jù)庫,同樣會面臨高并發(fā)導致數(shù)據(jù)庫崩潰的問題,系統(tǒng)瓶頸明顯不可取。

          2. 這里再加緩存的話,解決緩存問題會讓業(yè)務變得更復雜,結(jié)合第二個主要問題:瞬時高流量毛刺。


          最終方案:


          1. 庫存扣減成功后異步生成優(yōu)惠券,達到整體流程支持高并發(fā),且可以解決流量毛刺的問題。PS:分布式事務問題。

          2. 結(jié)合自身業(yè)務場景,對比權衡了多種分布式事務解決方案,最終選用本地事務表+最大努力通知來解決分布式事務問題。



          介紹:


          通過消息異步生成優(yōu)惠券落庫處理來支持高并發(fā),引入一張本地事務表達成數(shù)據(jù)的最終一致性。


          主流程如圖:



          數(shù)據(jù)參考:


          1. 結(jié)合自身實際業(yè)務測試環(huán)境壓測目標 1W/TPS 示意(系統(tǒng)整體支持橫向擴容進一步提升性能)。


          示意:




          05



          后續(xù)優(yōu)化

             5.1 熱點問題


          回顧整體方案,同批次場景仍存在熱點問題,針對這里可以做一些優(yōu)化來提升系統(tǒng)性能,如:資源分桶,聚合扣減,熱點更新技術等。如何解決熱點問題?下面結(jié)合發(fā)券場景列舉幾種方案做一下對比介紹,可供參考。


          熱點示意:



             5.1.1 資源分桶


          簡介同一個批次的庫存分成多份,通過分散庫存扣減請求提升性能。



          優(yōu)勢:水平擴展能力強。


          重點關注:

          1. 分桶 Key 路由傾斜問題,理想情況是所有 Key 平均對應分桶。

          2. 各桶之間庫存傾斜與性能權衡的問題,理想情況是所有分桶消耗速率一致。


             5.1.2 聚合扣減


          簡介:聚合相同批次的請求統(tǒng)一扣減,通過聚合請求量來提升服務整體性能。



          優(yōu)勢:前置聚合請求利于提高服務穩(wěn)定性。


          重點關注:

          1. 聚合策略的設計需要在系統(tǒng)穩(wěn)定性和性能上做取舍。

          2. 臨界庫存如何與聚合策略適配的問題。


             5.1.3 熱點更新


          簡介:熱點更新技術詳細介紹見騰訊云文檔:

          https://cloud.tencent.com/document/product/237/13402


          優(yōu)勢:適用數(shù)據(jù)庫鎖層面的熱點優(yōu)化。


          重點關注:

          1. 依賴數(shù)據(jù)庫適用場景較單一。


          小結(jié):每種方案的實現(xiàn)均有利有弊,最后都需要在系統(tǒng)性能和復雜度上做權衡取舍,最終選出契合自身實際業(yè)務的才是最好的方案。


          -End-
          原創(chuàng)作者|管振盼


           


          關于優(yōu)惠券系統(tǒng)的設計,你還有哪些心得體會?歡迎評論留言。我們將選取1則優(yōu)質(zhì)的評論,送出騰訊Q哥公仔1個(見下圖)。11月20日中午12點開獎。


          ????歡迎加入騰訊云開發(fā)者社群,享前沿資訊、大咖干貨,找興趣搭子,交同城好友,更有鵝廠招聘機會、限量周邊好禮等你來~


          (長按圖片立即掃碼)


          瀏覽 1055
          12點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          12點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕第一页精品 | 午夜成人网站 | 能看熟女不卡视频 | 无码精品一区 | 在线免费看不卡黄色视频 |