1. 程式人生 > 資料庫 >解密Redis助力雙11背後電商秒殺系統(推薦)

解密Redis助力雙11背後電商秒殺系統(推薦)

背景

秒殺活動是絕大部分電商選擇的低價促銷,推廣品牌的方式。既可以給平臺帶來使用者量,還可以提高平臺知名度。一個好的秒殺系統,可以提高平臺系統的穩定性和公平性,獲得更好的使用者體驗,提升平臺的口碑,從而提升秒殺活動的最大價值。

本文討論雲資料庫Redis版快取設計高併發的秒殺系統。

秒殺的特徵

秒殺活動對稀少或特價的商品進行定時定量售賣,吸引成大量的消費者進行搶購,但又只有少部分消費者可以下單成功。因此,秒殺活動將在一定時間內產生比平時大幾十倍倍,上百倍的頁面訪問流量和下單請求流量。

秒殺活動可以分為3個階段:

  • 秒殺前:使用者不斷重新整理商品詳情頁,頁面請求達到臨時開頭。
  • 秒殺開始:使用者點選秒殺按鈕,下單請求達到暫時提前。
  • 秒殺後:一部分成功下單的使用者不斷重新整理訂單或產生退單操作,大部分使用者繼續重新整理商品詳情頁等待退單機會。

消費者提交的訂單,一般做法是利用資料庫的行級鎖,只有搶到鎖的請求可以進行庫存查詢和下單操作。但是在高併發的情況下,資料庫無法承受如此大的請求,往往需要整個服務被阻止,在消費者看來就是伺服器停機機。

秒殺系統

解密Redis助力雙11背後電商秒殺系統(推薦)

利用系統的層次結構,在每個階段提前重新驗證,攔截無效流量,可以減少大量無效的流量湧入資料庫。

利用瀏覽器快取和CDN抗壓靜態頁面流量

因此,我們需要把秒殺商品詳情頁與普通的商品詳情頁分開。關於秒殺商品詳情頁試圖將能靜態化的元素靜態化處理,除了秒殺按鈕需要服務端進行動態判斷,其他的靜態資料可以快取在瀏覽器和CDN上。這樣,秒殺前重新整理頁面導致的流量進入服務端的流量只有很小的一部分。

利用識讀分離Redis快取攔截流量

CDN是第一級流量攔截,第二級流量攔截我們使用支援讀寫分離的Redis。在這一階段我們主要讀取資料,讀取分離Redis能支援高達60萬以上qps,完全可以支援需求。

首先通過資料控制模組,提前將秒殺商品快取到識別符號分離Redis,並設定秒殺開始標記如下:

"goodsId_count": 100 //總數
"goodsId_start": 0 //開始標記
"goodsId_access": 0 //接受下單數
  • 秒殺開始前,服務重新讀取goodsId_Start為0,直接返回未開始。
  • 資料控制模組將goodsId_start改為1,標誌秒殺開始。
  • 服務最大化快取開始標記位並開始接受請求,並記錄到redis中goodsId_access,商品剩餘數量為(goodsId_count-goodsId_access)。
  • 當接受下單數達到goodsId_count後,繼續攔截所有請求,商品剩餘數量為0。

可以拋光,最後成功參與下單的請求只有少部分可以被接受。在高併發的情況下,允許稍微多的流量進入。因此可以控制接受下單數的比例。

利用主從版Redis快取加速庫存扣量

成功避免下單後,進入下層服務,開始進行訂單資訊校驗,庫存扣量。為了避免直接訪問資料庫,我們使用主從版Redis來進行庫存扣量,主從版Redis提供10萬等級的QPS。使用Redis來優化庫存查詢,提前攔截秒殺失敗的請求,將大大提高系統的整體穩定性。

通過資料控制模組提前將庫存存入Redis,將每個秒殺商品在Redis中用一個hash結構表示。

"goodsId" : {
 "Total": 100
 "Booked": 100
}

扣量時,伺服器通過請求Redis獲取下單資格,通過以下lua指令碼實現,通過Redis是單執行緒模型,lua可以保證多個命令的原子性。

local n = tonumber(ARGV[1])
if not n or n == 0 then
 return 0
end
local vals = redis.call("HMGET",KEYS[1],"Total","Booked");
local total = tonumber(vals[1])
local blocked = tonumber(vals[2])
if not total or not blocked then
 return 0
end
if blocked + n <= total then
 redis.call("HINCRBY","Booked",n)
 return n;
end
return 0

先使用SCRIPT LOAD將lua指令碼EVALSHA預先快取在Redis,然後呼叫呼叫指令碼,比直接呼叫EVAL節省網路頻寬:

redis 127.0.0.1:6379>SCRIPT LOAD "lua code"
"438dd755f3fe0d32771753eb57f075b18fed7716"
redis 127.0.0.1:6379>EVAL 438dd755f3fe0d32771753eb57f075b18fed7716 1 goodsId 1

秒殺服務通過判斷Redis是否返回搶購個數n,即可知道此次請求是否扣量成功。

使用主從版Redis實現簡單的訊息非同步下單入庫

如果商品數量減少的時候,直接操作資料庫即可。如果秒殺的商品是1萬,甚至10萬等級,那資料庫鎖衝突將帶來很大的效能優勢。。因此,利用訊息元件,當秒殺服務將訂單資訊寫入訊息變數後,即可認為下單完成,避免直接操作資料庫。

訊息模組元件依然可以使用Redis實現,在R2中用列表資料結構表示。

```java
  orderList {
   [0] = {訂單內容}
   [1] = {訂單內容}
   [2] = {訂單內容}
   ...
  }

將訂單內容寫入

```java
 LPUSH orderList {訂單內容}

初步下單模組從Redis中順序獲取訂單資訊,將訂單寫入資料庫。

```java
  BRPOP orderList 0

通過使用Redis作為訊息收發器,非同步處理訂單入庫,有效的提高了使用者的下單完成速度。

資料控制模組管理秒殺資料同步

最開始,利用識別分離Redis進行流量限制,只讓部分流量進入下單。對於下單檢驗失敗和退單等情況,需要讓更多的流量進來。因此,資料控制模組需要定時將資料庫中的資料進行一定的計算,同步到主從版Redis,同時再同步到讀寫分離的Redis,讓更多的流量進來。

總結

到此這篇關於解密Redis助力雙11背後電商秒殺系統的文章就介紹到這了,更多相關redis電商秒殺系統內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!