電商庫存系統設計案例詳解(上)
1 庫存扣減
多人同時買一件商品時(假設庫存充足),每個人幾乎同時下單成功,給人一種並行感覺。但真實情況, 庫存只是一個數值,無論是存在 mysql 數據庫還是 redis 緩存,減值時都要控制順序,只能串行來扣減,當然爲保證安全性,會設計一些鎖控制。
1.1 關鍵技術點
-
• 同一個 SKU,庫存數量是共享
-
• 剩餘庫存要大於等於本次扣減的數量,否則超賣
-
• 對同一個數量多用戶併發扣減時,要注意併發安全,保證數據的一致性
-
• 類似於秒殺這樣高 QPS 的扣減場景,要保證性能與高可用
-
• 對於購物車下單場景,多個商品庫存批量扣減,要保證事務
-
• 如果有 交易退款 ,保證庫存扣減可返還
-
•
-
• 返還的數據總量不能大於扣減的總量
-
• 返還要保證冪等
-
• 可以分多次返還
1.2 數據庫扣減
主要依賴數據庫特性,保證扣減的一致性,邏輯簡單,開發部署成本低。
1.2.1 依賴的數據庫特性
-
• 依賴數據庫的樂觀鎖(如版本號或者庫存數量)保證數據併發扣減的強一致性
-
• 事務,針對購物車下單批量扣減時,部分扣減失敗,數據回滾
最上面會查詢當前的剩餘庫存(可能不準確,但沒關係,這裏只是第一步粗略校驗),前置校驗,如果已經沒有庫存,前置攔截生效,減少數據庫寫。畢竟讀操作不涉及加鎖,併發性能高。
2 數據庫表
2.1 庫存表
create table t_inventory
(
sku_id bigint null comment '商品規格 id',
leaved_amount int null comment '剩餘可購買數量'
);
-
• 當用戶取消訂單,申請退貨、退款,需將數量加回來
-
• 若商家補庫存,需在此基礎額外加上增量庫存
2.2 流水錶
create table t_inventory_flow
(
id bigint auto_increment comment '主鍵 id'
primary key,
sku_id int null comment '商品規格 id',
order_detail_id mediumtext null comment '訂單明細 id',
quantity_trade int null comment '本次購買扣減的數量'
);
-
• 用於查看明細、對賬、盤貨、排查問題
-
• 扣減後,某些場景下做返還,也還依賴流水
2.3 單條商品的扣減 SQL
update inventory
set leaved_amount = leaved_amount - #{count}
where sku_id='123' and leaved_amount >= #{count}
樂觀鎖實現原子性,在 where 條件裏判斷此次購買的數量≤剩餘的數量。在扣減服務的代碼,判斷此 SQL 的返回值,若:
-
• 值爲 1 ,表示扣減成功
-
• 否則,返回 0 ,表示庫存不足,需回滾
2.4 扣減成功後,記錄扣減的流水,並與訂單明細記錄關聯
-
1. 當用戶歸還數量時,需帶回此編號,標識此次返還屬於歷史上的具體哪次扣減。
-
2. 進行冪等控制。當用戶調用扣減接口出現超時,因爲用戶不知道是否成功,用此編號進行重試或反查。在重試時,使用此編號進行標識防重
3 數據庫扣減方案:第一次升級
極端例子:秒殺庫存只有 5 件,活動期間峯值 QPS 10W,活動結束後,上面的流水錶最終只會插入 5 條記錄,但查詢 QPS 10W。
所以,數據庫扣減方案第一次升級主要針對 庫存前置校驗 模塊的優化,作爲前置攔截器,承載流量很大,若將流量全部壓到主庫,很容易把數據壓垮。
考慮數據庫架構升級:
採用讀寫分離,新增加一套從庫,藉助 MySQL 自帶的數據同步能力。 庫存校驗時讀從庫。
當然,數據同步有時延,從庫數據有滯後性,所以這庫存校驗結果不準確,但能攔截大部分無效流量 。最終能不能成功購買,由主庫的 樂觀扣減 SQL 控制,不會影響最終扣減的準確性。
大大減輕主庫查詢壓力。
4 數據庫扣減方案:第二次升級
引入了從庫,確實能分攤主庫很大一部分壓力,但面對秒殺萬級 QPS,MySQL 的 千級 TPS 支撐不了,需進一步升級讀性能。
-
• 此時引入緩存中間件(如 Redis),將 mysql 的數據定時同步到緩存中
-
• 庫存校驗 模塊,從 redis 中查詢剩餘的庫存數據。由於緩存基於內存操作,性能比數據庫高出幾個數量級,單臺 redis 實例可以達到 10W QPS 的讀性能
該方案升級後,基本上解決在前置 【庫存校驗】 環節及 【獲取庫存數量接口】 的性能問題,提高系統整體性能。
tips
若併發量還很高,可考慮引入 緩存集羣 ,將不同的 秒殺商品 sku 儘量均勻分佈在多 redis 節點,分攤整體的峯值 QPS 壓力。
5 數據庫方案評價
優點
-
• ACID 超賣 少買
-
• 實現簡單,若工期緊張或開發資源不足,很適用
缺陷
- • 若參與秒殺的 SKU 很多,最後的寫操作都是基於 庫存主庫 ,性能壓力大
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Yh_XkOC2zdb8d-VZuYI-Rg