redis秒殺系統(tǒng)的實現(xiàn)
1.如何設(shè)計一個秒殺系統(tǒng)
在設(shè)計任何系統(tǒng)之前,我們首先都需要先理解秒殺系統(tǒng)的業(yè)務(wù)背景
下面我簡單的舉一個例子:
在某個時間點,某某電商網(wǎng)站要低價賣某件商品,而且限量1千件,搶購人數(shù)超過數(shù)十萬人。
所以我們面臨的第一個秒殺的問題就是:時間極短,然后瞬間流量非常大
我們的系統(tǒng)必須保證秒殺搶購的結(jié)果不出錯,達到搶購的預(yù)期目的。
而且秒殺庫存的實現(xiàn)也需要保障秒殺結(jié)果的準確性。
總結(jié)幾個特點就是:
- 高性能:秒殺中有大量的并發(fā)讀寫,所以需要使系統(tǒng)能支撐起高并發(fā)訪問,這是一個關(guān)鍵點。
- 高可用:藐視瞬間流量非常大,很有可能會導(dǎo)致系統(tǒng)宕機,所以需要從各方面保證系統(tǒng)的可用性。
- 一致性:由于秒殺請求量非常大,此時就需要我們的秒殺結(jié)果要準確。因為一旦出錯,那么波及面會非常廣,損失非常大。
2.秒殺流程
我們先從秒殺的入口開始說起
在秒殺入口的地方會有這些問題需要解決:
2.1 前端處理
靜態(tài)資源處理
秒殺商品一般都會包含很多靜態(tài)資源,所以這些圖片什么的靜態(tài)資源一定要放到CDN(Content Delivery Network,即內(nèi)容分發(fā)網(wǎng)絡(luò)),能放的盡量放進去。讓秒殺時后端服務(wù)器的壓力盡可能小。
說到此處,我重點描述講解CDN
為了能在傳統(tǒng)IP網(wǎng)上發(fā)布豐富的寬帶媒體內(nèi)容,提出在現(xiàn)有互聯(lián)網(wǎng)基礎(chǔ)上建立一個內(nèi)容分發(fā)平臺專門為網(wǎng)站提供服務(wù)。由于CDN是為加快網(wǎng)絡(luò)訪問速度而被優(yōu)化的網(wǎng)絡(luò)覆蓋層,因此被形象地稱為“網(wǎng)絡(luò)加速器”。
首先要說的是應(yīng)用服務(wù)器和資源服務(wù)器應(yīng)該解耦,也就是應(yīng)用服務(wù)器只處理邏輯,而資源服務(wù)器存放內(nèi)容或者叫資源。
- CDN專注于「內(nèi)容」,也就是CDN的C所代表的Content,專注于靜態(tài)資源的分發(fā)和訪問,比如一張圖片,一個文本文件,一個視頻,一個CSS,一個JS等等,任何以文件形式存儲的,為了提高在互聯(lián)網(wǎng)上的訪問速度和質(zhì)量,都可以將這個資源部署在CDN這個網(wǎng)絡(luò)上。
- CDN動作是「分發(fā)」,也就是如何讓剛才提到的那些「內(nèi)容」快速的部署在這個網(wǎng)絡(luò)中,從而快速為用戶服務(wù),其實還有一層更重要的含義是用戶的快速訪問與就近接入,分發(fā)的目的是為了用戶更好的體驗。
- CDN落定于「網(wǎng)絡(luò)」,是部署于全國或者全世界的一大堆服務(wù)器,這些服務(wù)器基于當(dāng)前互聯(lián)網(wǎng)的基礎(chǔ)架構(gòu)在其上層再構(gòu)成一個網(wǎng)絡(luò),這個網(wǎng)絡(luò)專為資源分發(fā)而生。
那CDN的原理是什么呢?為什么用戶可以接入離他最近的服務(wù)器呢?
主要是利用了DNS來判斷用戶位置,再返回給用戶最近的機房的服務(wù)器的資源地址。
下面我再通俗的解釋一下:
肯德基的總部在美國,可是你家樓下也有一家肯德基,并且漢堡包是一模一樣的,這就是CDN(這個比喻來自知乎,覺得非常的恰當(dāng))??系禄渴鹆撕芏鄠€CDN在世界各地提供服務(wù),用戶都是找到最近的店,這個計算過程就是剛才講的「就近接入」。
什么是CDN的調(diào)度呢?
(1)DNS調(diào)度是最常用和最通用的調(diào)度方案,缺點是存在DNS劫持的風(fēng)險,調(diào)度的精確度也會差一些;
(2)302調(diào)度非常適合用在大文件下載和視頻點播這兩個應(yīng)用場景,優(yōu)點是可以提高調(diào)度的精確度,缺點是將會增加首包的時延(在大文件下載和視頻點播場景下對首包時延不太敏感,而對調(diào)度精確度要求更高)
(3)HTTPDNS調(diào)度的優(yōu)點是有較高的安全性(可以規(guī)避DNS劫持風(fēng)險)和調(diào)度精確度,但是有個很大的缺點,需要客戶端提供支持(例如在手機APP上嵌入SDK),通用性較差。

通俗來講:
在一個商圈有兩家肯德基,有一家組織活動,雞腿隨便吃,所以顧客全部涌到這家店,已經(jīng)水泄不通,另一家店則門可羅雀。這個時候CDN的調(diào)度功能就要發(fā)揮作用了,另一家店也發(fā)布了一個消息說,買一個漢堡,打五折。這個時候,在第一家店搶不上雞腿的顧客,馬上跑去了第二家店,這個時候兩個店的流量處于均衡狀態(tài)。這就是CDN的調(diào)度。
惡意訪問行為的處理
當(dāng)我們推出秒殺活動后,還需要考慮黃牛黨們開發(fā)出的各種秒殺器,可以自動填單,自動回答各種問題,以及自動模擬點擊等,令我們防不勝防。
針對這些我們可以通過各種工作來限制和識別這些惡意訪問。
- 例如限制IP的提交次數(shù)
- 提高各種動態(tài)驗證碼及問題的難度
- 增加黑名單賬戶
秒殺鏈接隱藏
如果稍微懂點程序的人可以提前拿到秒殺鏈接,那么就可以通過程序在最快的時間發(fā)起秒殺請求,這樣人家就可以拿到大部分商品了。為了防止這一點,可以使秒殺鏈接動態(tài)化。使用MD5算法等加密隨機字符串作為URL的一部分,秒殺開始后才將連接放出來,同時在后臺進行校驗,此時已經(jīng)可以防止一大批的羊毛黨了。
前端限流
可以在秒殺按鈕點擊之后灰掉幾秒鐘,幾秒鐘之內(nèi)只能點擊一次。
可以使用Nginx用戶請求到Nginx的時候?qū)⒘髁糠稚⒌蕉鄠€服務(wù)器上,而且也可以針對用戶進行一些過濾,將一些請求攔截,保證后端的穩(wěn)定性。比如1萬個商品,最多放進來10萬個請求就可以了,其他的用戶就只能等著靜態(tài)頁面嘍。同時也可以在秒殺預(yù)約的時候隨機發(fā)放一些token,只有擁有這些token的客戶才有可能搶購成功。
同時在分布式的架構(gòu)下,我們也可以通過gateway,redis+lua或者nginx進行限流
2.2 后端處理
后端限流
如果服務(wù)的流量到達最大值的時候,新的請求就不能再進來了。
而服務(wù)宕機的時候也需要引導(dǎo)請求到備用服務(wù)器上面,然后返回一些靜態(tài)提示頁面等。
隔離就要求,秒殺的服務(wù)單獨部署,只承擔(dān)其秒殺的單一職責(zé),即使出問題,也不會影響其他的服務(wù)。
削峰
秒殺流量在某一個時間點非常高,那么我們讓瞬間進來的流量進到一個緩沖池,然后再進行平緩處理。比較多用到的方案就是使用消息隊列來處理。
庫存預(yù)熱
由于秒殺的商品的數(shù)量一般都是提前已知的,這時我們可以提前將商品的一些數(shù)據(jù)提前加載到緩存中。并且可以將商品分區(qū)來進行秒殺,根據(jù)每個大區(qū)的用戶數(shù)量以及活躍程度,為每個大區(qū)分配單獨的秒殺商品數(shù)量。這樣也可以分散服務(wù)器壓力。
使用緩存
高并發(fā)的情況下必然會遇到緩存雪崩,緩存擊穿,緩存穿透等問題。而且秒殺的場景是讀多寫少,使用Redis作為緩存非常合適,為了避免單臺Redis服務(wù)器出問題,導(dǎo)致緩存擊穿等問題,升級使用Redis集群是一個比較好的方案。提升可用性的性能也可以大大提高。
下面我簡單說一下緩存雪崩,緩存擊穿以及緩存穿透
首先我們要先了解一下緩存的處理流程
前臺請求,后臺先從緩存中取數(shù)據(jù),取到直接返回結(jié)果,取不到時從數(shù)據(jù)庫中取,數(shù)據(jù)庫取到更新緩存,并返回結(jié)果,數(shù)據(jù)庫也沒取到,那直接返回空結(jié)果。

知道什么是緩存之后我們重點來了解一下這三個名次具體指什么,以及如何去解決
緩存穿透
描述:緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù),而用戶不斷發(fā)起請求,如發(fā)起為id為“-1”的數(shù)據(jù)或id為特別大不存在的數(shù)據(jù)。這時的用戶很可能是攻擊者,攻擊會導(dǎo)致數(shù)據(jù)庫壓力過大。
解決方案:
- 接口層增加校驗,如用戶鑒權(quán)校驗,id做基礎(chǔ)校驗,id<=0的直接攔截;
- 從緩存取不到的數(shù)據(jù),在數(shù)據(jù)庫中也沒有取到,這時也可以將key-value對寫為key-null,緩存有效時間可以設(shè)置短點,如30秒(設(shè)置太長會導(dǎo)致正常情況也沒法使用)。這樣可以防止攻擊用戶反復(fù)用同一個id暴力攻擊
緩存擊穿
描述: 緩存擊穿是指緩存中沒有數(shù)據(jù)但數(shù)據(jù)庫中有的數(shù)據(jù)(一般是緩存時間到期),這時由于并發(fā)用戶特別多,同時讀緩存沒讀到數(shù)據(jù),又同時去數(shù)據(jù)庫去取數(shù)據(jù),引起數(shù)據(jù)庫壓力瞬間增大,造成過大壓力。
解決方案:
- 設(shè)置熱點數(shù)據(jù)永遠不過期。
- 加互斥鎖,互斥鎖參考代碼如下

我簡單解釋一下代碼思路:
我們首先從緩存中獲取數(shù)據(jù),如果數(shù)據(jù)不存在,我們則去獲取鎖,這把鎖 只需要能夠互斥,可重入即可,最簡單的就是redis的setnx來實現(xiàn),獲取鎖資源以后,從數(shù)據(jù)庫讀取數(shù)據(jù),同時將數(shù)據(jù)更新至緩存,然后釋放鎖;如果獲取鎖資源失敗,我們就讓其隔一段時間之后重新嘗試去獲取鎖資源。
緩存雪崩
緩存雪崩是指緩存中數(shù)據(jù)大批量到過期時間,而查詢數(shù)據(jù)量巨大,引起數(shù)據(jù)庫壓力過大甚至down機。
和緩存擊穿不同的是,緩存擊穿指并發(fā)查同一條數(shù)據(jù),緩存雪崩是不同數(shù)據(jù)都過期了,很多數(shù)據(jù)都查不到從而查數(shù)據(jù)庫。
解決方案:
- 緩存數(shù)據(jù)的過期時間設(shè)置隨機,防止同一時間大量數(shù)據(jù)過期現(xiàn)象發(fā)生。
- 如果緩存數(shù)據(jù)庫是分布式部署,將熱點數(shù)據(jù)均勻分布在不同搞得緩存數(shù)據(jù)庫中。
- 設(shè)置熱點數(shù)據(jù)永遠不過期。
3.超賣問題
秒殺中一個重要的點就是超賣問題,由于搶購人數(shù)多,流量也很大,但是也不能賣多了。
目前常見的解決方案就是:
1.數(shù)據(jù)庫要加唯一索引,減庫存的時候要先進行庫存數(shù)量判斷等,數(shù)據(jù)庫鎖,加版本號的樂觀鎖方式等等。2
.采用Redis來維護庫存,由于秒殺活動可以預(yù)先知道商品的數(shù)量,所以可以提前將商品的數(shù)據(jù)加載到Redis中,如果Redis的庫存不足的話則秒殺失敗。
3.生成訂單的時候?qū)⒄埱蠓诺椒?wù)端的異步隊列中去處理,可以使用Redis的隊列,或者MQ均可。
4.總體思路
其實秒殺方案的總體思路也很簡單:
1.盡可能的將請求攔截在上游;
2.后端均要處理限流;
3.盡量減少請求到數(shù)據(jù)庫;
4.多利用緩存;
5.使用異步操作-可以使用隊列等;
6.秒殺服務(wù)單一職責(zé);
7.盡早失敗,讓秒殺請求返回
到此這篇關(guān)于redis秒殺系統(tǒng)的實現(xiàn)的文章就介紹到這了,更多相關(guān)redis 秒殺系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis遍歷海量數(shù)據(jù)集的幾種實現(xiàn)方法
Redis作為一個高性能的鍵值存儲數(shù)據(jù)庫,廣泛應(yīng)用于各種場景,包括緩存、消息隊列、排行榜,本文主要介紹了Redis遍歷海量數(shù)據(jù)集的幾種實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02
在Centos?8.0中安裝Redis服務(wù)器的教程詳解
由于考慮到linux服務(wù)器的性能,所以經(jīng)常需要把一些中間件安裝在linux服務(wù)上,今天通過本文給大家介紹下在Centos?8.0中安裝Redis服務(wù)器的詳細過程,感興趣的朋友一起看看吧2022-03-03

