百億級流量紅包系統,如何做架構?(字節面試真題)

文章很長,且持續更新,建議收藏起來,慢慢讀!瘋狂創客圈總目錄 博客園版 爲您奉上珍貴的學習資源 :

免費贈送 :《尼恩Java面試寶典》 持續更新+ 史上最全 + 面試必備 2000頁+ 面試必備 + 大廠必備 +漲薪必備
免費贈送 :《尼恩技術聖經+高併發系列PDF》 ,幫你 實現技術自由,完成職業升級, 薪酬猛漲!加尼恩免費領
免費贈送 經典圖書:《Java高併發核心編程(卷1)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 經典圖書:《Java高併發核心編程(卷2)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 經典圖書:《Java高併發核心編程(卷3)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領

免費贈送 資源寶庫: Java 必備 百度網盤資源大合集 價值>10000元 加尼恩領取


百億級流量紅包系統,如何做架構?(字節面試真題)

尼恩特別說明: 尼恩的文章,都會在 《技術自由圈》 公號 發佈, 並且維護最新版本。 如果發現圖片 不可見, 請去 《技術自由圈》 公號 查找

尼恩說在前面

在40歲老架構師 尼恩的讀者交流羣(50+)中,最近有小夥伴拿到了一線互聯網企業如得物、阿里、滴滴、極兔、有贊、希音、百度、網易、美團的面試資格,遇到很多很重要的架構類/設計類的場景題:

1.如何設計高併發紅包系統 ,請說出你的方案?

2.聽說你會架構設計,請問一下如果讓你來設計紅包系統,說說你的架構設計方案。

最近有小夥伴在面試字節,又遇到了紅包架構問題。小夥伴支支吾吾的說了幾句,面試掛了。

所以,尼恩給大家做一下系統化、體系化的梳理,使得大家內力猛增,可以充分展示一下大家雄厚的 “技術肌肉”,讓面試官愛到 “不能自已、口水直流”,然後實現”offer直提”。

當然,這道面試題,以及參考答案,也會收入咱們的 《尼恩Java面試寶典PDF》V171版本,供後面的小夥伴參考,提升大家的 3高 架構、設計、開發水平。

最新《尼恩 架構筆記》《尼恩高併發三部曲》《尼恩Java面試寶典》的PDF,請關注本公衆號【技術自由圈】獲取,回覆:領電子書

本文的2個重量級作者:

第一重量級作者 Moen(資深架構師,負責寫初稿 )
第二重量級作者 尼恩 (40歲老架構師, 負責提升此文的 技術高度,讓大家有一種 俯視 技術的感覺)
《尼恩Java面試寶典》 是大家 面試的殺手鐗, 此文當最新PDF版本,可以找43歲老架構師尼恩獲取。

紅包架構背景

紅包是一種 瞬時流量很大的應用, 會在很短的時間內,產生巨大的瞬時流量,

所以,作爲架構師來說,這種場景有很大的架構挑戰

以2017年除夕爲例,微信紅包峯值QPS在76w左右,除夕當天收發微信紅包的數量爲142億個。

這種百億級別的數據量、100Wqps級別的超高併發,而且整個系統核心功能和支付相關,需要做好高併發、高可用、高可靠。

特別說明:紅包架構也是高端面試的核心場景題, 後面也會以視頻的形式,對這些架構的一系列的架構場景題目,做系統化的介紹。

尼恩架構團隊會錄製成爲架構視頻, 幫助大家做架構拿高薪。

紅包系統和秒殺系統的對比

我們先了解下微信紅包支付的流程。

在上面的紅包流程中,核心業務包含包紅包、發紅包、搶紅包、拆紅包

其中最關鍵的步驟是

  • 發紅包

  • 搶紅包。

在整個體系中,紅包系統 是 支付系統的商戶,紅包這個商戶出售的是錢。

所以,用戶發紅包在紅包系統 使用微信支付購買一份 紅包商品,紅包系統 將錢發放到相對應的微信羣,供參與者領取。

微信羣裏的用戶搶紅包,得到的是商品裏邊的 零錢。

在整個體系中,紅包系統 和支付系統 之間的關係是商家和第三方支付平臺的關係。

紅包的流程,很類似 商品“秒殺”活動。

  • 包紅包類似秒殺商品管理
  • 發紅包類似“秒殺”活動的商品上架;
  • 搶紅包等同於“秒殺”活動中的查詢庫存;
  • 拆紅包對應“秒殺”活動中用戶的“秒殺”動作。

不過除了上面的相同點之外,紅包業務 與 “秒殺”活動相比,還具備自身的特點:

首先,搶紅包 比 “秒殺”有更海量的併發要求。假設同一時間有 10 萬個羣裏的用戶同時在發紅包,那就相當於同一時間有 10 萬個“秒殺”活動發佈出去。10 萬個微信羣裏的用戶同時搶紅包,將產生海量的併發請求。

其次,微信紅包業務要求更嚴格的安全級別。紅包業務本質上是資金交易。資金交易業務比普通商品“秒殺”活動有更高的安全級別要求。

  • “秒殺”時可以允許存在“超賣”(即實際被搶的商品數量比計劃的庫存多)、“少賣”(即實際被搶的商戶數量比計劃的庫存少)的情況。

  • 但是對於 紅包,不允許存在“超賣”、“少賣”。

特別說明:紅包架構也是高端面試的核心場景題, 後面也會以視頻的形式,對這些架構的一系列的架構場景題目,做系統化的介紹。

尼恩架構團隊會錄製成爲架構視頻, 幫助大家做架構拿高薪。

紅包系統功能分析

接下來,40歲老架構帶大家,從架構師視角開始紅包系統的功能分析。

微信紅包和微信支付之間的交互,與普通商家與微信支付的交互一樣,需要經過多個步驟。

  • 用戶發紅包時,進入微信紅包下一筆訂單,系統記錄發紅包用戶、發紅包金額、紅包數量和要發送到的用微信羣。

  • 然後微信紅包系統請求微信支付服務器進行下單,用戶使用微信支付進行支付。

  • 支付成功後,微信支付後臺系統通知微信紅包後臺系統支付成功結果,微信紅包後臺系統收到通知後推送微信紅包消息到微信羣。

  • 微信羣裏用戶便可搶紅包。

  • 用戶發現紅包還有剩餘,就可以拆剩下的紅包

這就是微信紅包和微信支付的關係以及交互過程。

功能1:包紅包

系統給每個紅包分配一個唯一ID,也就是發紅包的訂單號,然後將紅包發送給用戶,紅包的個數,紅包金額寫入到存儲。

功能2:發紅包

用戶使用微信支付完成付款,微信紅包後臺收到微信支付成功的通知。紅包系統將紅包發送訂單狀態更新,更新爲用戶已支付,並寫入用戶發紅包記錄表,這樣用戶可以在錢包中找到用戶的發紅包流水和收發紅包的記錄,之後微信紅包系統調用微信通知,將微信紅包信息發送到微信羣。

功能3:搶紅包

微信羣中的用戶收到紅包消息之後,點開紅包,開始搶紅包,這個過程微信紅包系統會檢查紅包是否已經被搶完,是否已經過期,是否已經搶過等驗證邏輯。

功能4:拆紅包

拆紅包是整個發紅包流程最複雜的一個操作,需要查詢這個紅包的紅包訂單,判斷用戶是否可以拆包,計算本次可拆到的紅包金額,並記錄搶紅包流水。

拆紅包包括如下步驟:

  • 1)查詢這個紅包發送訂單,判斷用戶是否可拆,然後計算本次可拆到的紅包金額;

  • 2)然後寫入一條搶紅包記錄。如果把拆紅包過程,類比爲一個秒殺活動的過程,相當於扣庫存與寫入秒殺記錄的過程;

  • 3)更新庫存對應於更新紅包發送訂單,寫入秒殺記錄對應於寫入這個紅包的領取紅包記錄;

  • 4)另外,還要寫入用戶整體的紅包領取記錄;

  • 5)最後請求微信支付系統給拆到紅包用戶轉入零錢,成功後更新搶紅包的訂單狀態爲已轉賬成功。

拆紅包過程類似於一個秒殺活動的過程,需要做好庫存扣減和秒殺記錄的操作。

更新庫存就是更新紅包發送的訂單,寫入秒殺記錄就是寫入紅包領取的信息流水。

還需要以用戶爲中心記錄用戶整體的紅包領取記錄。

最後調用支付系統將拆紅包後的金額轉入用戶零錢中,成功之後更新搶紅包的訂單狀態爲轉賬成功。

所以,在看此文之前,最好看看尼恩的高併發三部曲的Java高併發核心編程卷3*(注意是最新的清華大學出版社出版的加強版),裏邊有秒殺架構,可以作爲知識鋪墊。

微信紅包的業務特點

微信紅包,特別是羣紅包,業務形態上類似於普通商品的"秒殺"活動。

  • 包紅包類似秒殺商品管理

  • 發紅包類似“秒殺”活動的商品上架;

  • 搶紅包等同於“秒殺”活動中的查詢庫存;

  • 拆紅包對應“秒殺”活動中用戶的“秒殺”動作。

    微信紅包在業務形態上和普通商品"秒殺"活動相比,還有自身特點:

  1. 海量併發請求:微信紅包用戶在微信羣發一個紅包,等同於在網上發佈一次商品"秒殺"活動,假設同時有10萬個羣的用戶同時發紅包,那就相當於同一時間有10萬個"秒殺"活動發佈。10萬個微信羣的用戶同時搶紅包,將產生海量併發請求。

  2. 更嚴格的安全級別:微信紅包業務本質上是資金交易,微信紅包是微信支付的一個商戶,提供資金流轉服務,用戶發紅包相當於在微信紅包這個商戶上使用微信支付購買了一筆"錢",且收貨地址是微信羣。當用戶支付成功後,紅包"發貨"到微信羣裏,羣裏的用戶拆開紅包後,微信紅包提供了將"錢"轉入拆紅包用戶微信零錢的服務。

  3. 訂單層南北獨立體系:微信紅包系統採用南北獨立體系的訂單層設計,即數據在南北兩個系統中不同步。用戶就近接入系統,請求發紅包時,系統會根據用戶所在地分配訂單到南或北的系統,並在訂單號上打上南北標識。這種設計有助於分攤流量,降低系統風險。

  4. 流量閉環:在搶紅包、拆紅包、查紅包詳情列表時,接入層會根據紅包單號上的南北標識,將流量分別引導到對應的南北系統閉環。這意味着,無論是發紅包還是搶紅包,用戶都能夠在就近的系統中完成操作,無需跨城,提高了系統的響應速度和穩定性。

  5. 用戶數據處理:微信紅包系統的用戶數據採取寫多讀少、全量保存的策略。用戶數據的查詢入口在微信錢包中,相對隱藏,訪問量不會太大,且被視爲可旁路的非關鍵信息,實時性要求不高。這種設計方式可以減少數據存儲的壓力,提高系統性能。

  6. 實時計算紅包金額

    微信紅包的金額是在拆紅包時實時計算的,而不是預先分配的。系統會在拆紅包時取0.01到剩餘平均值*2之間的數值作爲紅包金額。

    這種實時計算的方式基於內存進行,不需要額外的存儲空間,且計算效率很高。

    同時,爲了保證操作的原子性,拆包過程中使用了CAS(Compare-and-Swap)算法,確保每次只有一個併發用戶拆包成功。如果拆包CAS失敗,系統會自動進行重試,但也可能在重試過程中被其他用戶搶得先機而空手而歸。

  7. 架構演進:隨着微信紅包功能的不斷髮展和用戶量的增長,其系統架構也經歷了不斷的演進和優化。從最初的數據庫硬抗整個流量,到後來的使用緩存(cache)抗流量,再到現在的南北獨立體系等設計,都是爲了更好地應對高併發、提升系統性能和穩定性。

    資金交易業務比普通商品"秒殺"有更高的安全級別要求,普通的商品"秒殺"由商戶提供,庫存是商戶預設,"秒殺"允許存在超賣和少賣的情況,但對於微信紅包,用戶發100元的紅包絕對不可以拆出101元,以及只被領取99元時,剩下的1元在24小時過期後要精準退還給發紅包用戶。

    總的來說,微信紅包系統架構的設計充分考慮了用戶量、併發量、性能要求等因素,通過南北獨立體系、流量閉環、用戶數據處理、實時計算紅包金額以及架構演進等多種手段,保證了系統的穩定運行和良好用戶體驗。

微信紅包的技術難點

微信紅包系統架構的技術難點主要體現在以下幾個方面:

  1. 高併發難點

    微信紅包在特定時間(如春節、節假日等)會面臨極高的併發量,如何有效地處理這些併發請求,保證系統的穩定性和響應速度,是紅包系統架構設計的關鍵挑戰之一。

  2. 資金安全難點

    紅包系統涉及到資金的轉移和存儲,因此資金安全是系統設計的重中之重。如何確保資金安全,防止被攻擊或篡改,是系統架構設計中需要重點考慮的問題。

    紅包業務涉及資金交易,所以一定不能出現超賣、少賣的情況。

    • 超賣:發了 10 塊錢,結果搶到了 11 塊錢,多的錢只能系統補上,如此爲愛發電應用估計早就下架了;

    • 少賣:發了 10 塊錢,只搶了 9 塊,多的錢得原封不動地退還用戶,否則第二天就接到法院傳單了。

  3. 用戶體驗難點

    紅包系統需要保證良好的用戶體驗,包括響應速度、公平性(先搶先得)、成功率等。

    如何在高併發場景下保證用戶體驗,是系統架構設計的重要目標。

    瞭解下微信紅包的用戶體驗 的4大核心:搖/發/搶/拆。

    • 搖:搖的流暢

    • 快:搶的要快

    • 爽:拆的爽

    • 穩:能分享出去

  4. 數據一致性難點

    紅包系統需要保證數據的一致性,包括紅包庫存數據、用戶賬戶數據等。如何在高併發場景下保證數據的一致性,是系統架構設計的重要挑戰。

    • 參與用戶越多,併發 DB 請求越大,數據越容易出現事務問題,所以系統得做好事務一致性

    • 搶紅包系統涉及金錢交易,所以事務級別要求更高,不能出現髒數據

  5. 系統擴展性難點

    隨着用戶量和業務量的增長,紅包系統需要具備良好的擴展性,能夠方便地增加新的功能或提升性能。

    如何設計可擴展的系統架構,是系統架構設計的重要考慮因素。

    爲了解決這些技術難點,我們可以採用多種技術手段,如分而治之、負載均衡、讀寫分離、水平切分、垂直切分等,來提升系統的性能和穩定性。同時,系統還採用了柔性服務、系統降級等策略,來保證在有限資源下滿足用戶的核心需求。

紅包系統概要設計

系統功能說明

搶紅包功能允許用戶在羣聊中發送任意個數和金額的紅包,羣成員可以搶到隨機金額的紅包,但要保證每個用戶的紅包金額不小於 0.01 元

搶紅包的詳細交互流程如下:

  1. 用戶接收到搶紅包通知,點擊通知打開羣聊頁面;

  2. 用戶點擊搶紅包,後臺服務驗證用戶資格,確保用戶尚未領取過此紅包;

  3. 若用戶資格驗證通過,後臺服務分配紅包金額並存儲領取記錄;

  4. 用戶在微信羣中看到領取金額,紅包狀態更新爲“已領取”;

  5. 異步調用支付接口,將紅包金額更新到錢包裏。

數據庫設計

紅包表:redpack

紅包表用來記錄用戶發了多少紅包,以及需要維護的剩餘金額,

紅包表:redpack的字段如下:

字段 描述
id 主鍵,紅包ID。
user_id 發送紅包的用戶id。
total_amount 紅包總金額。
surplus_amount 紅包剩餘金額。
total 紅包總數。
surplus_total 剩餘紅包總數。

紅包記錄表:redpack_record

字段 描述
id 主鍵,記錄id。
redpack_id 紅包id。
user_id 用戶id。
amount 搶到的金額。

發紅包

設置完紅包參數後,微信支付,完成付款,然後收到付款成功通知,紅包系統更新紅包訂單狀態,更新爲已支付,並寫入紅包發送記錄表。

這樣用戶可以將用戶的紅包信息和紅包的收發記錄發出,紅包系統調用微信通知,將紅包信息發送到微信羣。

發紅包的交互步驟如下:

  1. 用戶設置紅包的總金額和個數後,在紅包表中增加一條數據,開始發紅包;

  2. 爲了保證實時性和搶紅包的效率,在 Redis 中增加一條記錄,存儲紅包 ID 和總人數 n

  3. 搶紅包消息推送給所有羣成員。

搶紅包

微信羣用戶收到紅包後,點開,紅包系統會校驗紅包是否被搶完,是否過期。

微信紅包的搶紅包和拆紅包是兩個分離的服務,用戶點擊搶紅包後需要進行兩次操作。

這也是爲什麼明明有時候搶到了紅包,點開後卻發現該紅包已經被領取完了

搶紅包的交互步驟如下:

  1. 搶紅包:搶操作在 Redis 緩存層完成,通過原子遞減的操作來更新紅包個數,個數遞減爲 0 後就說明搶光了。

  2. 拆紅包:拆紅包時,首先會實時計算金額,一般是通過二倍均值法實現(即 0.01 到剩餘平均值的 2 倍之間)。

  3. 紅包記錄:用戶獲取紅包金額後,通過數據庫的事務操作累加已經領取的個數和金額,並更新紅包表和記錄表。

  4. 轉賬:爲了提升效率,最終的轉賬爲異步操作,這也是爲什麼在春節期間,紅包領取後不能立即在餘額中看到的原因。

紅包系統詳細設計

紅包整體架構

如下圖所示,是微信紅包的系統架構

總體是三層架構:

  • 首先是微信統一接入層,下面是微信紅包系統 API,包括髮、搶、拆、查紅包詳情、查紅包用戶列表。

  • 接入層下面,是封裝微信紅包關鍵業務的邏輯服務;

  • 業務下面數據存儲層,微信紅包最主要的數據是訂單數據,包括髮紅包訂單和拆紅包訂單兩部分。

數據存儲層的冷熱分離設計:微信紅包數據的訪問熱度,隨着時間流逝會急劇降低,也就是數據的訪問時間段非常集中,一般紅包發出三天後,99% 的用戶不會再去點開這個紅包了。因此微信紅包系統採取按時間做冷熱數據分離,降低數據的存儲成本,同時提升了熱數據的訪問性能。

除了在線計算的三層架構,還有離線處理的數據分析。

數據分析平臺用於對紅包數據的分析計算,比如朋友圈裏的文章,統計從 某年 1 月 1 日到 2017 年 1 月一個用戶總共搶紅包的金額,在全國的排名情況,發紅包數最多的城市等。

數據分析平臺另外一個作用就是對賬,紅包的訂單和微信支付的訂單需要對賬,以保證最終資金的一致性;

  • 訂單的數據和訂單的 cache 需要做對賬,以保證數據的完整性;

  • 訂單數據和用戶的收發記錄需要對賬,以保證用戶列表完整性。

高併發常用解決方案

普通商品秒殺系統,解決高併發問題的方案,大致有以下2種:

1- 使用內存替代實時的DB

將實時扣庫存的行爲上移到內存Cache中,內存Cache操作成功直接給Server返回成功,然後異步落DB持久化。

這個方案的優缺點如下:

優點:用內存操作替代磁盤操作,提高了併發性能。

缺點:在內存操作成功DB持久化失敗,或者內存Cache故障的情況下,DB持久化會丟數據,不適合微信紅包這種資金交易系統。

2- 使用樂觀鎖替代悲觀鎖

什麼是悲觀鎖呢?

所謂悲觀鎖,是關係數據庫管理系統裏的一種併發控制的方法。它可以阻止一個事務以影響其他用戶的方式來修改數據。如果一個事務執行的操作對某行數據應用了鎖,那只有當這個事務把鎖釋放,其他事務才能夠執行與該鎖衝突的操作。對應於上文分析中的“併發請求搶鎖”行爲。

什麼是樂觀鎖呢?

所謂樂觀鎖,它假設多用戶併發的事務在處理時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分數據。在提交數據更新之前,每個事務會先檢查在該事務讀取數據後,有沒有其他事務又修改了該數據。如果其他事務有更新的話,正在提交的事務會進行回滾。

樂觀鎖分爲DB樂觀鎖和 JVM CAS 樂觀鎖。

DB樂觀鎖的具體應用方法,是在 DB 的“庫存”記錄中維護一個版本號。

商品“秒殺”系統中,在更新“庫存”的操作進行前,先去 DB 獲取當前版本號。

在更新庫存的事務提交時,檢查該版本號是否已被其他事務修改。如果版本沒被修改,則提交事務,且版本號加 1;如果版本號已經被其他事務修改,則回滾事務,並給上層報錯。

DB樂觀鎖可以提高DB的併發處理能力,但是如果應用於微信紅包系統,則會存在下面三個問題:

  1. 如果拆紅包採用樂觀鎖,那麼在併發搶到相同版本號的拆紅包請求中,只有一個能拆紅包成功,其他的請求將事務回滾並返回失敗,給用戶報錯,用戶體驗完全不可接受。

  2. 如果採用樂觀鎖,將會導致第一時間同時拆紅包的用戶有一部分直接返回失敗,反而那些“手慢”的用戶,有可能因爲併發減小後拆紅包成功,這會帶來用戶體驗上的負面影響。

  3. 如果採用樂觀鎖的方式,會帶來大數量的無效更新請求、事務回滾,給 DB 造成不必要的額外壓力。

JVM CAS 樂觀鎖方案

出於性能原因,微信紅包系統使用 JVM CAS 樂觀鎖,而不是DB樂觀鎖的方式解決併發搶鎖問題。

微信紅包的金額是在拆紅包時實時計算的,而不是預先分配的。系統會在拆紅包時取0.01到剩餘平均值*2之間的數值作爲紅包金額。

這種實時計算的方式基於JVM 內存進行,不需要額外的存儲空間,且計算效率很高。

同時,爲了保證操作的原子性,拆包過程中使用了CAS(Compare-and-Swap)算法,確保每次只有一個併發用戶拆包成功。如果拆包CAS失敗,系統會自動進行重試,但也可能在重試過程中被其他用戶搶得先機而空手而歸。

如何保證同一個紅包由同一個節點去拆包呢?將同一個紅包 ID 的所有請求 stick 到同一臺 Server,這個後面介紹。

以上內容比較複雜,尼恩架構團隊會錄製成爲架構視頻, 幫助大家做架構拿高薪。

微信紅包系統的高併發解決方案

綜合上面的分析,我們的紅包系統針對相應的技術難點,採用如下3個方案,解決高併發問題。

1- 分而治之:系統架構設計垂直Set化。

什麼是Set(單元)化架構呢?

單元化架構是一種將系統劃分爲多個獨立的、自包含的單元的部署架構,每個單元都能夠完成所有業務操作,包含所有業務所需的服務以及分配給該單元的數據。這種架構將單元作爲部署的基本單位,在全站所有機房中部署多個單元,每個機房內的單元數目不固定,但任一單元均部署系統所需的全部應用。數據則是全量數據按照某種維度劃分後的一部分。與傳統意義上的SOA(服務化)架構不同,單元化架構下,服務仍然是分層的,但每一層中的任意一個節點都屬於且僅屬於某一個單元,上層調用下層時,僅會選擇本單元內的節點。

通俗的理解爲

單元化架構,簡單來說,就是把系統拆分成若干個獨立的單元,每個單元都包含了完成業務操作所需的所有服務和數據。這些單元可以獨立部署、管理和監控,就像一個個小房子,每個房子都有自己的客廳、臥室和廚房(服務),也有自己的食物和水(數據)。

如下圖,是一種單元化架構設計。

微信紅包用戶發一個紅包時,微信紅包系統生成一個 ID 作爲這個紅包的唯一標識。

接下來這個紅包的所有發紅包、搶紅包、拆紅包、查詢紅包詳情等操作,都根據這個 ID 關聯。

紅包系統根據這個紅包 ID,按一定的規則(如按 ID 尾號取模等),垂直上下切分。

切分後,一個垂直鏈條上的邏輯 Server 服務器、DB 統稱爲一個 SET。

各個 SET 之間相互獨立,互相解耦。並且同一個紅包 ID 的所有請求,包括髮紅包、搶紅包、拆紅包、查詳情詳情等,垂直 stick 到同一個 SET 內處理,高度內聚。

通過這樣的方式,系統將所有紅包請求這個巨大的洪流分散爲多股小流,互不影響,分而治之,如下圖所示。

這個方案解決了同時存在海量事務級操作的問題,將海量化爲小量

2- 解決DB併發:邏輯Server層將請求排隊。

紅包系統是資金交易系統,DB 操作的事務性無法避免,所以會存在“併發搶鎖”問題。但是如果到達 DB 的事務操作(也即拆紅包行爲)不是併發的,而是串行的,就不會存在“併發搶鎖”的問題了。

按這個思路,爲了使拆紅包的事務操作串行地進入 DB,只需要將請求在 Server 層以 FIFO(先進先出)的方式排隊,就可以達到這個效果。從而問題就集中到 Server 的 FIFO 隊列設計上。

紅包系統設計了分佈式的、輕巧的、靈活的 FIFO 隊列方案。其具體實現如下:

1)將同一個紅包 ID 的所有請求 stick 到同一臺 Server。

上面 SET 化方案已經介紹,同個紅包 ID 的所有請求,按紅包 ID stick 到同個 SET 中。

不過在同個 SET 中,會存在多臺 Server 服務器同時連接同一臺 DB(基於容災、性能考慮,需要多臺 Server 互備、均衡壓力)。

爲了使同一個紅包 ID 的所有請求,stick 到同一臺 Server 服務器上,在 SET 化的設計之外,微信紅包系統添加了一層基於紅包 ID hash 值的分流,如下圖所示。

以上內容比較複雜,尼恩架構團隊會錄製成爲架構視頻, 幫助大家做架構拿高薪。

2)設計單機請求排隊方案。

將 stick 到同一臺 Server 上的所有請求在被接收進程接收後,按紅包 ID 進行排隊。

然後串行地進入 worker 進程(執行業務邏輯)進行處理,從而達到排隊的效果,如下圖所示。

3)增加 Redis緩存 控制併發。

爲了防止 Server 中的請求隊列過載導致隊列被降級,從而所有請求擁進 DB,系統增加了與 Server 服務器同機部署的 Redis ,用於控制拆同一個紅包的請求併發數。

具體來說,利用 Redis 的 CAS 原子累增操作,控制同時進入 DB 執行拆紅包事務的請求數,超過預先設定數值則直接拒絕服務。用於 DB 負載升高時的降級體驗。

通過以上三個措施,系統有效地控制了 DB 的“併發搶鎖”情況。

3- 系統性能穩定性保障:雙維度分庫分表設計。

紅包系統的分庫表規則,初期是根據紅包 ID 的 hash 值分爲多庫多表。

隨着紅包數據量逐漸增大,單表數據量也逐漸增加。而 DB 的性能與單表數據量有一定相關性。當單表數據量達到一定程度時,DB 性能會有大幅度下降,影響系統性能穩定性。

採用冷熱分離,將歷史冷數據與當前熱數據分開存儲,可以解決這個問題。

處理微信紅包數據的冷熱分離時,系統在以紅包 ID 維度分庫表的基礎上,增加了以循環天分表的維度,形成了雙維度分庫表的特色。

具體來說,就是分庫表規則像 db_xx.t_y_dd 設計,其中,xx/y 是紅包 ID 的 hash 值後三位,dd 的取值範圍在 01~31,代表一個月天數最多 31 天。

通過這種雙維度分庫表方式,解決了 DB 單表數據量膨脹導致性能下降的問題,保障了系統性能的穩定性。同時,在熱冷分離的問題上,又使得數據搬遷變得簡單而優雅。

綜上所述,微信紅包系統在解決高併發問題上的設計,主要採用了 SET 化分治請求排隊雙維度分庫表等方案,使得單組 DB 的併發性能大幅度提升,取得了很好的效果。

紅包分配算法

搶紅包後,我們需要進行拆紅包,接下來我們討論一下紅包系統的紅包分配算法。

紅包金額分配時,由於是隨機分配,所以有兩種實現方案:實時拆分和預先生成

1- 實時拆分

實時拆分,指的是在搶紅包時實時計算每個紅包的金額,以實現紅包的拆分過程。

這個對系統性能和拆分算法要求較高,例如拆分過程要一直保證後續待拆分紅包的金額不能爲空,不容易做到拆分的紅包金額服從正態分佈規律。

2- 預先生成

預先生成,指的是在紅包開搶之前已經完成了紅包的金額拆分,搶紅包時只是依次取出拆分好的紅包金額。

這種方式對拆分算法要求較低,可以拆分出隨機性很好的紅包金額,但通常需要結合隊列使用。

3- 二倍均值法

綜合上述優缺點考慮,以及微信羣聊中的人數不多(目前最高 500 人),所以我們採用實時拆分的方式,用二倍均值法來生成隨機紅包,只滿足隨機即可,不需要正態分佈。

使用二倍均值法生成的隨機數,每次隨機金額會在  0.01 ~ 剩餘平均值*2 之間。

假設當前紅包剩餘金額爲 10 元,剩餘個數爲 5,10/5 = 2,則當前用戶可以搶到的紅包金額爲:**0.01 ~ 4 **元之間。

以下是使用Java實現的二倍均值算法,在紅包分配場景中。

public class RedPacketDistribution {

    public static List<BigDecimal> distribute(BigDecimal totalAmount, int totalCount) {
        // 校驗總金額是否爲正
        if (totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Invalid parameter, totalAmount must be positive.");
        }
        // 校驗紅包總數是否至少爲1
        if (totalCount < 1) {
            throw new IllegalArgumentException("Invalid parameter, totalCount must be at least 1.");
        }

        List<BigDecimal> redPacketList = new ArrayList<>(totalCount);
        BigDecimal remainingAmount = totalAmount.multiply(BigDecimal.valueOf(2)); // 初始化爲總金額的兩倍
        ThreadLocalRandom random = ThreadLocalRandom.current(); // 使用線程安全的隨機數生成器

        for (int i = 0; i < totalCount - 1; i++) {
            // 隨機獲取一個幸運值,範圍在[0, 當前剩餘金額)
            BigDecimal luckValue = BigDecimal.valueOf(random.nextDouble()).multiply(remainingAmount);
            // 計算並添加實際分配的紅包金額(幸運值的一半)
            BigDecimal amount = luckValue.divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_DOWN);
            redPacketList.add(amount);
            // 更新剩餘金額
            remainingAmount = remainingAmount.subtract(luckValue);
        }

        // 最後一個紅包直接拿走剩餘的全部金額,確保總和正確
        redPacketList.add(remainingAmount.divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_DOWN));

        return redPacketList;
    }

    public static void main(String[] args) {
        BigDecimal totalAmount = new BigDecimal("100.00"); // 紅包總金額
        int totalCount = 10;      // 紅包個數
        List<BigDecimal> redPackets = distribute(totalAmount, totalCount);

        System.out.println("Red packet distribution:");
        for (BigDecimal amount : redPackets) {
            System.out.printf("%.2f, ", amount);
        }
    }
}

以上內容比較複雜,尼恩架構團隊會錄製成爲架構視頻, 幫助大家做架構拿高薪。

紅包系統高可用架構設計

紅包業務量級的高速發展,對後臺系統架構的可用性要求越來越高。在保障微信紅包業務體驗的前提下,紅包後臺系統進行了一系列高可用方面的優化設計。

要保障紅包系統架構的高可用性,可以從多個方面進行優化和設計。以下是一些詳細說明:

  1. 系統架構設計

    • 信息流、業務流、資金流分離:紅包系統由信息流、業務流、資金流三部分組成,這三部分在組織架構上應由不同的後臺團隊完成,以提高系統的模塊化和可維護性。
    • 微服務架構:採用微服務架構,將紅包系統拆分成多個獨立的服務,每個服務負責特定的功能,這樣可以提高系統的可擴展性和容錯性。
    • 無狀態設計:確保紅包系統的服務是無狀態的,即服務不需要保存用戶的會話信息,這樣可以提高系統的併發處理能力和可靠性。
  2. 高可用性策略

    • 冗餘部署:將系統的關鍵組件部署在多臺服務器上,通過搭建主備或者集羣的架構來實現冗餘。當主服務器出現故障時,備用服務器能夠自動接管,保證系統的可用性。
    • 負載均衡:通過將流量分發到多臺服務器上,均衡系統的請求負載,提高系統的可用性和擴展性。負載均衡可以通過硬件(如負載均衡器)或者軟件(如Nginx、HAProxy)實現。
    • 服務容器化:使用容器技術(如Docker、Kubernetes)將應用程序與其依賴項打包爲容器,實現快速部署、彈性擴展和自動化管理。容器化可以提高系統的可移植性、彈性和可伸縮性,從而增加系統的高可用性。
  3. 數據保障

    • 數據備份與恢復:定期對關鍵數據進行備份,並確保備份的數據可用性。這樣,在發生數據丟失或損壞時,可以快速恢復數據,減少系統停機時間。
    • 分佈式緩存:使用多級緩存技術(如Redis、Memcached等),將數據分別存儲在內存緩存、本地緩存和分佈式緩存中,以提高訪問速度和降低數據庫壓力。
    • 數據一致性:使用分佈式鎖技術來保護紅包的領取操作,確保每個用戶只能領取一次紅包。同時,爲了保證數據一致性,可以採用消息隊列等技術實現請求的異步處理和結果的返回。
  4. 監控與告警

    • 系統監控:對紅包系統的關鍵指標(如請求量、響應時間、錯誤率等)進行實時監控,以便及時發現和解決潛在問題。
    • 告警機制:設置合理的告警閾值,當系統出現異常情況時,及時發送告警通知給相關人員,以便快速響應和處理。
  5. 安全性保障

    • 訪問控制:實施嚴格的訪問控制策略,確保只有授權的用戶才能訪問紅包系統。
    • 數據加密:對敏感數據進行加密存儲和傳輸,以防止數據泄露和篡改。
    • 安全審計:定期對紅包系統進行安全審計和漏洞掃描,及時修復發現的安全漏洞和隱患。

    通過以上措施的綜合應用,可以大大提高紅包系統架構的高可用性,確保系統在高峯時段能夠穩定、高效地運行。

1 - 系統可用性影響因素

系統的可用性影響因素可分成兩類:

  • 一類計劃外;

    計劃外包含很多因素,系統用到的所有東西都可能產生故障,都可能成功影響可用性的因素。從這個角度上來講,可以說故障是無法避免的,系統的運作一定會產生故障,尤其是服務器有成千上萬個的時候。

  • 一類計劃內。

    計劃內的影響因素,主要有與升級相關、運維相關的操作,以及日常的備份等。這一類影響因素,通過精細地設計方案,是可以避免對可用性造成影響的。

2 - 紅包系統可用性設計方向

基於上面兩個分析結論,可以總結出紅包系統的可用性的設計方向。

1.在不能避免意外故障的情況下,儘可能降低出現意外故障時對可用性的影響。

2.絕大多數計劃內的日常維護可以通過方案的設計避免影響可用性,其中平行擴容特指關於存儲層的平行擴容。

下面從降低故障影響和微信紅包系統的平行擴容兩方面進行分析。

首先是降低意外故障的影響,重點講解訂單存儲層在訂單 DB 故障的情況下如何降低對紅包系統可用性的影響。

3 - 業務邏輯層 - 部署方案設計

首先是業務邏輯層的部署方案。業務邏輯層是無狀態的,微信紅包系統的業務邏輯層,部署在兩個城市,即兩地部署,每一個城市部署至少三個園區,即三個 IDC。並且每個服務需要保證三個 IDC 的部署均衡。另外,三個 IDC 總服務能力需要冗餘三分之一,當一個 IDC 出現故障時,服務能力仍然足夠。從而達到 IDC 故障不會對可用性產生影響。

4 - 業務邏輯層 - 異步化設計

如下圖所示,微信紅包的某些步驟不實時完成也不會影響用戶對紅包業務可用性的體驗。

比如拆紅包,正常的業務流程很長,但關鍵步驟只有訂單相關的幾步。

至於轉零錢、寫紅包記錄等操作不需要實時。

用戶搶到紅包時,一般不會實時去錢包查看微信零錢,而是在微信羣中點開消息查看本次搶到金額和他人搶紅包金額。

所以拆紅包時只需要從 cache 查詢用戶是否拆過紅包,然後寫入拆紅包的訂單記錄,更新發紅包訂單,其他的操作都可以異步化。

當然,不是每個業務都可以進行異步化設計,需要進行業務分析,判斷是否存在非關鍵步驟之外的事情可以將其異步化,並通過異步對賬保證最終一致。

經過上述分析之後,可以採用如下思路與方案:

實現思路:

1.最簡關鍵路徑:簡化發紅包、拆紅包核心流程路徑,重點關注與訂單相關流程。

2.快慢分離:將核心流程與其他非關鍵步驟分離。

方案:

1.寫用戶記錄、零錢入賬使用MQ異步執行

2.增加對帳機制保障最終一致。

如上圖所示,微信紅包的某些步驟不實時完成也不會影響用戶對紅包業務可用性的體驗。

比如拆紅包,正常的業務流程很長,但關鍵步驟只有訂單相關的幾步。

至於轉零錢、寫紅包記錄等操作不需要實時。

用戶搶到紅包時,一般不會實時去錢包查看微信零錢,而是在微信羣中點開消息查看本次搶到金額和他人搶紅包金額。

所以拆紅包時只需要從 cache 查詢用戶是否拆過紅包,然後寫入拆紅包的訂單記錄,更新發紅包訂單,其他的操作都可以異步化。

當然,不是每個業務都可以進行異步化設計,需要進行業務分析,判斷是否存在非關鍵步驟之外的事情可以將其異步化,並通過異步對賬保證最終一致。

以上內容比較複雜,尼恩架構團隊會錄製成爲架構視頻, 幫助大家做架構拿高薪。

5 - 訂單存儲層 - 故障自愈

爲解決 DB 間的相互影響,需要將 DB 間相互隔離,訂單存儲層 SET 化。

SET 化指訂單 DB 和訂單接入 SERVER 垂直 stick 一起。業務邏輯層訪問訂單時,根據訂單倒數第二、三位數字找到所屬訂單 SET,一個 SET 的請求不能路由到其他 SET。

通過 SET 化得到的好處是,控制 DB 連接數、隔離故障影響和分流併發。

如上圖所示,所設尾號 90-99 的 SET 故障時,如果業務邏輯服務後續不再生成屬於這個 SET 的訂單,那後續的業務就可以逐漸恢復。

也就是在發生故障時,業務邏輯層發佈一個版本,屏蔽故障號段的單號生成,就可以恢復業務。

進一步想,除了人爲發版本,有沒有方法可以讓 DB 故障時自動恢復?

在 DB 故障導致業務失敗時,業務邏輯層可獲取到故障 DB 的號段,在發紅包時,將這些故障的號段,換一個可用的號段就可恢復業務。

訂單號除了最後三位,前面的部分已能保證該紅包唯一性,後面的數字只代表着分庫表信息,故障時只需要將最後三位換另外一個 SET 便可自動恢復。

完成這個設計後,即使 DB 出現故障,業務的可用性也不會有影響。

這裏還有一點,新的發紅包請求可避免 DB 故障的影響,但那些故障之前已發出未被領取的紅包,紅包消息已發送到微信羣,單號已確定,拆紅包時還是失敗。

對這種情況,由於不會有增量,採用正常的主備切換解決即可。

6 - 訂單存儲層 - 平行擴容設計

紅包系統的高可用架構設計,主要包括了部署設計、SET 化設計、異步化設計、DB 故障自愈能力建設、平行擴容設計。

以上內容比較複雜,尼恩架構團隊會錄製成爲架構視頻, 幫助大家做架構拿高薪。

總結

紅包系統是一個高併發的資金交易系統,最大的技術挑戰是保障併發性能與資金安全。

這種全新的技術挑戰,傳統的“秒殺”系統設計方案已不能完全解決。

在分析了業界“秒殺”系統解決方案的基礎上,紅包系統採用了 SET 化、請求排隊串行化、雙維度分庫表等設計,形成了獨特的高併發、資金安全系統解決方案。

說在最後:有問題找老架構取經

超高併發紅包架構,一定是一個超級牛掰的簡歷亮點項目,黃金項目,稍微晚點把全量的架構方案和視頻進行發佈。

這個項目寫入簡歷,面試的時候如果大家能對答如流,如數家珍,基本上 面試官會被你 震驚到、吸引到。

最終,讓面試官愛到 “不能自已、口水直流”。offer, 也就來了。

在面試之前,建議大家系統化的刷一波 5000頁《尼恩Java面試寶典》V174,在刷題過程中,如果有啥問題,大家可以來 找 40歲老架構師尼恩交流。

另外,如果沒有面試機會,可以找尼恩來幫扶、領路。

  • 大齡男的最佳出路是 架構+ 管理
  • 大齡女的最佳出路是 DPM,

圖片

女程序員如何成爲DPM,請參見:

DPM (雙棲)陪跑,助力小白一步登天,升格 產品經理+研發經理

領跑模式,尼恩已經指導了大量的就業困難的小夥伴上岸。

前段時間,領跑一個40歲+就業困難小夥伴拿到了一個年薪100W的offer,小夥伴實現了 逆天改命

技術自由的實現路徑:

實現你的 架構自由:

喫透8圖1模板,人人可以做架構

10Wqps評論中臺,如何架構?B站是這麼做的!!!

阿里二面:千萬級、億級數據,如何性能優化? 教科書級 答案來了

峯值21WQps、億級DAU,小遊戲《羊了個羊》是怎麼架構的?

100億級訂單怎麼調度,來一個大廠的極品方案

2個大廠 100億級 超大流量 紅包 架構方案

… 更多架構文章,正在添加中

實現你的 響應式 自由:

響應式聖經:10W字,實現Spring響應式編程自由

這是老版本 《Flux、Mono、Reactor 實戰(史上最全)

實現你的 spring cloud 自由:

Spring cloud Alibaba 學習聖經》 PDF

分庫分表 Sharding-JDBC 底層原理、核心實戰(史上最全)

一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之間混亂關係(史上最全)

實現你的 linux 自由:

Linux命令大全:2W多字,一次實現Linux自由

實現你的 網絡 自由:

TCP協議詳解 (史上最全)

網絡三張表:ARP表, MAC表, 路由表,實現你的網絡自由!!

實現你的 分佈式鎖 自由:

Redis分佈式鎖(圖解 - 秒懂 - 史上最全)

Zookeeper 分佈式鎖 - 圖解 - 秒懂

實現你的 王者組件 自由:

隊列之王: Disruptor 原理、架構、源碼 一文穿透

緩存之王:Caffeine 源碼、架構、原理(史上最全,10W字 超級長文)

緩存之王:Caffeine 的使用(史上最全)

Java Agent 探針、字節碼增強 ByteBuddy(史上最全)

實現你的 面試題 自由:

4800頁《尼恩Java面試寶典 》 40個專題

免費獲取11個技術聖經PDF:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章