保護高并發(fā)服務(wù)穩(wěn)定主要有三把利器:緩存、降級和限流
前言
在當今數(shù)字化時代,互聯(lián)網(wǎng)應(yīng)用面臨著前所未有的高并發(fā)挑戰(zhàn)。無論是電商平臺的促銷活動、社交媒體的熱點事件,還是在線游戲的高峰時段,大量用戶的同時訪問對服務(wù)的穩(wěn)定性構(gòu)成了巨大威脅。
隨著微服務(wù)的流行,服務(wù)之間的依賴性和調(diào)用關(guān)系變得越來越復(fù)雜,服務(wù)的穩(wěn)定性變得尤為重要。業(yè)務(wù)場景中經(jīng)常會涉及到瞬時流量沖擊,可能會導(dǎo)致請求響應(yīng)超時,甚至服務(wù)器被壓垮、宕機不可用。
出于對系統(tǒng)本身和上下游服務(wù)的保護,我們引入了緩存、降級和限流。
緩存
緩存是一種用于存儲經(jīng)常訪問的數(shù)據(jù)副本的技術(shù),其主要目的是減少對原始數(shù)據(jù)源(如數(shù)據(jù)庫)的訪問,從而顯著提升系統(tǒng)的響應(yīng)速度和吞吐量。在高并發(fā)環(huán)境下,緩存的作用尤為突出,它可以有效減輕后端數(shù)據(jù)源的負載壓力,防止其因大量請求而不堪重負。
工作原理
緩存的工作原理基于一個簡單而高效的機制:當應(yīng)用程序請求數(shù)據(jù)時,它首先會檢查緩存中是否已經(jīng)存在該數(shù)據(jù)。如果緩存命中,即數(shù)據(jù)已存在于緩存中,應(yīng)用程序可以直接從緩存中獲取數(shù)據(jù)并返回給用戶,這一過程幾乎是瞬間完成的。反之,如果緩存未命中,應(yīng)用程序則需要從原始數(shù)據(jù)源(如數(shù)據(jù)庫)中讀取數(shù)據(jù),然后將數(shù)據(jù)存儲到緩存中,以便后續(xù)請求能夠更快地獲取。
緩存的應(yīng)用層次
緩存可以應(yīng)用在多個層次,每個層次都有其獨特的優(yōu)勢和適用場景:
- 瀏覽器緩存:瀏覽器緩存是最接近用戶的緩存層次,它允許瀏覽器在本地存儲網(wǎng)頁資源(如
HTML、CSS、JavaScript
文件以及圖片等)。當用戶再次訪問相同的網(wǎng)頁時,瀏覽器可以直接從本地緩存中加載這些資源,而無需再次向服務(wù)器發(fā)送請求。這不僅大大加快了網(wǎng)頁的加載速度,還減少了網(wǎng)絡(luò)流量和服務(wù)器的負載。 CDN
緩存:內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN
)緩存通過在全球各地部署節(jié)點服務(wù)器,將靜態(tài)內(nèi)容(如圖片、視頻、腳本文件等)緩存到離用戶最近的節(jié)點上。當用戶請求這些內(nèi)容時,CDN
服務(wù)器可以直接從本地緩存中提供數(shù)據(jù),而無需將請求轉(zhuǎn)發(fā)回源服務(wù)器。CDN
緩存能夠顯著降低用戶的訪問延遲,提高網(wǎng)站的性能和可用性,尤其對于全球范圍內(nèi)的用戶訪問效果更為明顯。- 反向代理緩存:反向代理服務(wù)器位于應(yīng)用服務(wù)器之前,它可以緩存應(yīng)用服務(wù)器的響應(yīng)結(jié)果。當有新的請求到達時,反向代理首先檢查緩存中是否存在匹配的響應(yīng),如果存在,則直接返回給客戶端,而無需將請求轉(zhuǎn)發(fā)給應(yīng)用服務(wù)器。反向代理緩存可以有效減輕應(yīng)用服務(wù)器的負載,提高系統(tǒng)的整體性能。常見的反向代理服務(wù)器軟件如
Nginx、Apache
等都支持緩存功能。 - 應(yīng)用緩存:應(yīng)用緩存是在應(yīng)用程序內(nèi)部實現(xiàn)的緩存機制,它通常用于緩存應(yīng)用程序頻繁訪問的數(shù)據(jù)或計算結(jié)果。應(yīng)用緩存可以根據(jù)應(yīng)用的需求進行定制化開發(fā),靈活性較高。例如,在
Java
應(yīng)用中,可以使用Ehcache、Caffeine
等緩存框架來實現(xiàn)應(yīng)用緩存功能。
緩存的挑戰(zhàn)與解決方案
雖然緩存能夠帶來顯著的性能提升,但在實際應(yīng)用中也面臨一些挑戰(zhàn):
- 緩存穿透:緩存穿透是指查詢一個在緩存和數(shù)據(jù)庫中都不存在的數(shù)據(jù),導(dǎo)致每次請求都繞過緩存直接查詢數(shù)據(jù)庫。這種情況可能是由于惡意攻擊或者業(yè)務(wù)邏輯錯誤導(dǎo)致的。為了解決緩存穿透問題,可以采用以下幾種方法:
參數(shù)校驗:在應(yīng)用程序入口處對請求參數(shù)進行嚴格校驗,確保參數(shù)的合法性,例如檢查查詢 ID 是否為負數(shù)或超出合理范圍等。
布隆過濾器:布隆過濾器是一種高效的數(shù)據(jù)結(jié)構(gòu),它可以用于判斷一個元素是否存在于一個集合中。通過在緩存之前使用布隆過濾器,可以快速過濾掉不存在的數(shù)據(jù)請求,避免這些請求直接訪問數(shù)據(jù)庫。
緩存空值:當查詢數(shù)據(jù)庫未找到數(shù)據(jù)時,可以將空值緩存起來,并設(shè)置一個較短的過期時間,這樣在過期時間內(nèi)相同的請求將直接從緩存中獲取空值,而不會再次查詢數(shù)據(jù)庫。
- 緩存擊穿:緩存擊穿是指在緩存過期的瞬間,大量并發(fā)請求同時訪問該緩存對應(yīng)的數(shù)據(jù)庫數(shù)據(jù),導(dǎo)致數(shù)據(jù)庫壓力瞬間增大。為了解決緩存擊穿問題,可以考慮以下方法:
- 熱點數(shù)據(jù)永不過期:對于一些熱點數(shù)據(jù),可以設(shè)置其在緩存中永不過期,或者將過期時間設(shè)置得足夠長,以避免因緩存過期而導(dǎo)致的并發(fā)訪問問題。
- 加鎖機制:在從數(shù)據(jù)庫讀取數(shù)據(jù)并更新緩存時,可以使用分布式鎖或本地鎖來保證同一時間只有一個線程能夠訪問數(shù)據(jù)庫,其他線程等待鎖釋放后從緩存中獲取數(shù)據(jù)。這樣可以避免大量并發(fā)請求同時查詢數(shù)據(jù)庫。
- 緩存雪崩:緩存雪崩是指在某一時刻,大量緩存同時過期,導(dǎo)致大量請求同時涌向數(shù)據(jù)庫,造成數(shù)據(jù)庫壓力過大甚至崩潰。為了防止緩存雪崩,可以采取以下措施:
- 隨機過期時間:在設(shè)置緩存過期時間時,為每個緩存項設(shè)置一個隨機的過期時間,避免大量緩存同時過期。
- 多級緩存:采用多級緩存架構(gòu),例如同時使用內(nèi)存緩存和磁盤緩存。當內(nèi)存緩存失效時,可以從磁盤緩存中獲取數(shù)據(jù),從而減輕數(shù)據(jù)庫的壓力。
- 緩存預(yù)熱:在系統(tǒng)啟動時,提前將一些熱點數(shù)據(jù)加載到緩存中,避免在系統(tǒng)運行初期因緩存未命中而導(dǎo)致大量請求直接訪問數(shù)據(jù)庫。
降級
降級是在系統(tǒng)面臨高壓力或出現(xiàn)故障時采取的一種應(yīng)急策略,其核心思想是在資源有限的情況下,通過犧牲部分非核心業(yè)務(wù)的功能來保證核心業(yè)務(wù)的正常運行。降級策略可以幫助系統(tǒng)在極端情況下保持基本的可用性,避免因系統(tǒng)崩潰而導(dǎo)致的全面服務(wù)中斷。
降級的觸發(fā)條件
降級通常在以下幾種情況下觸發(fā):
- 系統(tǒng)負載過高:當系統(tǒng)的
CPU
、內(nèi)存、磁盤I/O
或網(wǎng)絡(luò)帶寬等資源利用率達到或超過設(shè)定的閾值時,表明系統(tǒng)負載過高,可能無法同時處理所有請求。此時,可以觸發(fā)降級策略,減少對資源消耗較大的非核心業(yè)務(wù)的處理,以保證核心業(yè)務(wù)有足夠的資源運行。 - 服務(wù)故障:當某個關(guān)鍵服務(wù)出現(xiàn)故障或不可用時,為了防止故障蔓延影響整個系統(tǒng),可能需要對依賴該服務(wù)的其他業(yè)務(wù)進行降級處理。例如,如果第三方支付接口出現(xiàn)故障,電商平臺可以暫時關(guān)閉在線支付功能,引導(dǎo)用戶選擇其他支付方式,同時保證商品瀏覽、下單等核心功能的正常運行。
- 網(wǎng)絡(luò)故障:在網(wǎng)絡(luò)不穩(wěn)定或出現(xiàn)大面積網(wǎng)絡(luò)故障時,為了避免因網(wǎng)絡(luò)延遲或超時導(dǎo)致用戶體驗惡化,可以對一些對網(wǎng)絡(luò)要求較高的非核心業(yè)務(wù)進行降級。比如,暫停實時數(shù)據(jù)同步功能,改為異步批量同步,以減少網(wǎng)絡(luò)請求的頻率和壓力。
降級的實現(xiàn)方式
降級可以在多個層次進行,常見的降級方式包括:
- 頁面降級:頁面降級是指在系統(tǒng)壓力較大時,將一些復(fù)雜的頁面簡化為靜態(tài)頁面或只展示核心信息。例如,在電商大促期間,為了減輕服務(wù)器壓力,可以將商品詳情頁中的一些動態(tài)元素(如實時推薦、用戶評價滾動條等)去掉,只保留商品基本信息、圖片和價格等核心內(nèi)容。這樣可以減少頁面渲染所需的資源和時間,提高頁面加載速度。
- 功能降級:功能降級是指關(guān)閉或限制一些非核心功能的使用。例如,在社交媒體平臺流量高峰時,可以暫時關(guān)閉圖片上傳、視頻播放等占用大量帶寬和資源的功能,只保留文字發(fā)布、點贊、評論等基本功能。這樣可以在保證用戶基本社交需求的同時,降低系統(tǒng)的負載壓力。
- 服務(wù)降級:服務(wù)降級是指對一些非核心服務(wù)進行降級處理,例如降低服務(wù)的響應(yīng)質(zhì)量或頻率。比如,在訂單處理系統(tǒng)中,當訂單量過大時,可以將訂單的實時處理改為異步處理,將一些非關(guān)鍵的訂單校驗邏輯簡化或延遲執(zhí)行,以提高訂單處理的吞吐量。同時,可以返回給用戶一個友好的提示信息,告知用戶訂單已提交成功,正在處理中,讓用戶了解訂單的狀態(tài)。
降級策略的制定與管理
制定降級策略需要綜合考慮業(yè)務(wù)的重要性、用戶體驗以及系統(tǒng)資源的實際情況。在制定降級策略時,需要注意以下幾點:
- 明確核心業(yè)務(wù)與非核心業(yè)務(wù):首先要對業(yè)務(wù)進行梳理和分類,明確哪些是核心業(yè)務(wù),哪些是非核心業(yè)務(wù)。核心業(yè)務(wù)是指對用戶體驗和業(yè)務(wù)運營至關(guān)重要的功能,如電商平臺的下單支付功能、社交媒體平臺的用戶登錄和信息發(fā)布功能等。非核心業(yè)務(wù)則是指那些對用戶體驗影響較小、可以在緊急情況下暫時犧牲的功能。
- 合理設(shè)置降級閾值:根據(jù)系統(tǒng)的性能指標和歷史數(shù)據(jù),合理設(shè)置降級的觸發(fā)閾值。閾值設(shè)置過低可能導(dǎo)致頻繁降級,影響用戶體驗;閾值設(shè)置過高則可能無法及時有效地保護系統(tǒng)。例如,可以根據(jù)系統(tǒng)的
CPU
使用率、內(nèi)存使用率、并發(fā)請求數(shù)等指標來設(shè)置降級閾值。 - 提供友好的用戶提示:在進行降級處理時,要及時向用戶提供友好的提示信息,告知用戶當前系統(tǒng)的狀態(tài)以及相關(guān)功能的調(diào)整情況。這樣可以避免用戶因功能異常而產(chǎn)生困惑和不滿,提高用戶的滿意度和信任度。例如,可以在頁面上顯示一個全局提示框,說明由于系統(tǒng)繁忙,部分功能已暫時調(diào)整,給用戶帶來的不便敬請諒解。
- 實時監(jiān)控與動態(tài)調(diào)整:建立實時監(jiān)控系統(tǒng),對系統(tǒng)的運行狀態(tài)、業(yè)務(wù)指標以及降級策略的執(zhí)行情況進行實時監(jiān)控。根據(jù)監(jiān)控數(shù)據(jù),及時發(fā)現(xiàn)問題并對降級策略進行動態(tài)調(diào)整。例如,如果發(fā)現(xiàn)某個非核心業(yè)務(wù)在降級后對用戶體驗影響較大,可以適當放寬該業(yè)務(wù)的降級條件;如果發(fā)現(xiàn)系統(tǒng)負載壓力進一步增大,可以進一步加強降級措施。
限流
流是一種通過限制系統(tǒng)處理請求的速率或數(shù)量來保護系統(tǒng)免受過載的技術(shù)。在高并發(fā)場景下,限流可以防止系統(tǒng)因瞬間涌入的大量請求而導(dǎo)致資源耗盡、響應(yīng)變慢甚至崩潰。限流就像一個閥門,能夠有效地控制進入系統(tǒng)的流量,確保系統(tǒng)在其處理能力范圍內(nèi)穩(wěn)定運行。
限流的目的與作用
限流的主要目的和作用包括以下幾個方面:
- 保護系統(tǒng)資源:系統(tǒng)的資源(如
CPU
、內(nèi)存、網(wǎng)絡(luò)帶寬、數(shù)據(jù)庫連接等)是有限的,當大量請求同時到達時,可能會導(dǎo)致資源耗盡。通過限流,可以將請求速率控制在系統(tǒng)能夠承受的范圍內(nèi),避免因資源過度消耗而導(dǎo)致系統(tǒng)故障。 - 保證服務(wù)質(zhì)量:當系統(tǒng)負載過高時,響應(yīng)時間會顯著增加,甚至出現(xiàn)超時現(xiàn)象,這將嚴重影響用戶體驗。限流可以確保系統(tǒng)在高并發(fā)情況下仍能保持一定的響應(yīng)速度和服務(wù)質(zhì)量,為用戶提供穩(wěn)定可靠的服務(wù)。
- 防止惡意攻擊:某些惡意攻擊者可能會通過發(fā)送大量請求來對系統(tǒng)進行
DDoS
(分布式拒絕服務(wù))攻擊,試圖使系統(tǒng)癱瘓。限流可以有效地抵御這類攻擊,通過限制單個IP
或用戶的請求速率,防止惡意請求對系統(tǒng)造成損害。
限流的常見算法
實現(xiàn)限流的關(guān)鍵在于選擇合適的算法,常見的限流算法有以下幾種:
圖片
令牌桶算法:令牌桶算法是一種廣泛應(yīng)用的限流算法。其核心思想是系統(tǒng)以固定的速率生成令牌,并將令牌放入一個桶中。當請求到達時,嘗試從桶中獲取令牌,如果桶中有足夠的令牌,則請求被允許通過;否則,請求將被拒絕或等待。令牌桶算法的特點是允許一定程度的突發(fā)流量,因為桶可以存儲一定數(shù)量的令牌,當有突發(fā)請求時,可以消耗桶中積累的令牌。例如,假設(shè)系統(tǒng)以每秒 10 個令牌的速率生成令牌,令牌桶的容量為 100 個。如果在某一時刻,桶中有 50 個令牌,此時突然來了 80 個請求,由于桶中有足夠的令牌(50 個),這 80 個請求中的 50 個可以立即通過,剩余 30 個請求則需要等待新的令牌生成或者被拒絕。
圖片
漏桶算法:漏桶算法與令牌桶算法類似,但工作方式略有不同。漏桶算法將請求看作水流,請求進入一個固定容量的桶中,桶以固定的速率將請求流出(即處理請求)。如果桶已滿,新的請求將被丟棄。漏桶算法的優(yōu)點是能夠平滑地處理請求,確保請求以穩(wěn)定的速率被處理,不會出現(xiàn)突發(fā)流量。但其缺點是對突發(fā)流量的處理能力較弱,當突發(fā)大量請求時,可能會導(dǎo)致部分請求被丟棄。例如,假設(shè)漏桶的容量為 100,流出速率為每秒 10 個請求。如果在某一時刻,突然來了 150 個請求,由于桶的容量限制,只能容納 100 個請求,剩余 50 個請求將被丟棄,而桶中的請求將以每秒 10 個的速率被逐步處理。
圖片
固定窗口計數(shù)器算法:固定窗口計數(shù)器算法是一種簡單直觀的限流算法。它將時間劃分為固定的窗口,例如每秒、每分鐘等,并在每個窗口內(nèi)統(tǒng)計請求的數(shù)量。當請求到達時,檢查當前窗口內(nèi)的請求數(shù)量是否超過了設(shè)定的閾值,如果超過,則拒絕該請求;否則,允許請求通過并將計數(shù)器加 1。固定窗口計數(shù)器算法的實現(xiàn)簡單,但存在明顯的臨界問題。例如,假設(shè)限流閾值為每分鐘 100 個請求,窗口時間為 1 分鐘。如果在第 1 分鐘的最后幾秒和第 2 分鐘的最初幾秒內(nèi),分別有 90 個請求到達,雖然在每個單獨的 1 分鐘窗口內(nèi)請求數(shù)量都未超過閾值,但在這兩個窗口的重疊時間段內(nèi),請求總數(shù)達到了 180 個,已經(jīng)超過了限流閾值,可能導(dǎo)致系統(tǒng)過載。
圖片
滑動窗口計數(shù)器算法:滑動窗口計數(shù)器算法是對固定窗口計數(shù)器算法的改進,它通過將大的時間窗口劃分為多個小的子窗口,每個子窗口獨立統(tǒng)計請求數(shù)量,并隨著時間的推移滑動窗口,從而更精確地控制請求速率。滑動窗口計數(shù)器算法能夠有效解決固定窗口計數(shù)器算法的臨界問題,提高限流的準確性。例如,將 1 分鐘的時間窗口劃分為 60 個 1 秒的子窗口,每個子窗口內(nèi)統(tǒng)計請求數(shù)量。當時間從第 1 秒滑動到第 2 秒時,第 1 秒的子窗口統(tǒng)計數(shù)據(jù)被移除,同時加入第 61 秒的子窗口統(tǒng)計數(shù)據(jù)。這樣,無論請求在時間上如何分布,都能更準確地進行限流控制。
四種基本算法的對比:
圖片
限流的應(yīng)用場景
限流在各種高并發(fā)場景中都有廣泛的應(yīng)用,以下是一些常見的應(yīng)用場景:
- 秒殺活動:在電商平臺的秒殺活動中,由于參與人數(shù)眾多,瞬間會產(chǎn)生大量的請求。通過限流可以控制每秒進入秒殺系統(tǒng)的請求數(shù)量,避免系統(tǒng)因高并發(fā)請求而崩潰,同時保證每個用戶都有公平參與秒殺的機會。例如,可以根據(jù)系統(tǒng)的處理能力,設(shè)置每秒只允許 1000 個請求進入秒殺系統(tǒng),超出部分的請求將被限流提示用戶稍后再試。
- API 接口訪問:對于一些提供對外 API 服務(wù)的平臺,為了保護自身系統(tǒng)的穩(wěn)定性和資源,需要對 API 接口的調(diào)用頻率進行限制。例如,限制每個用戶每分鐘最多調(diào)用某個 API 接口 100 次,超出次數(shù)的調(diào)用將返回錯誤信息,提示用戶調(diào)用頻率過高。這樣可以防止個別用戶或應(yīng)用程序濫用 API 接口,對平臺造成過大的壓力。
- 登錄注冊:在用戶登錄和注冊功能中,為了防止惡意用戶通過暴力破解密碼或頻繁注冊賬號進行攻擊,可以對單個 IP 地址或用戶的登錄注冊請求頻率進行限流。例如,限制每個 IP 地址每分鐘最多進行 5 次登錄嘗試或 10 次注冊操作,超出限制的請求將被暫時封禁一段時間,以提高系統(tǒng)的安全性。
- 視頻直播:在視頻直播場景中,為了保證直播的流暢性和穩(wěn)定性,需要對觀眾的并發(fā)訪問數(shù)量進行限流。例如,根據(jù)服務(wù)器的帶寬和處理能力,限制每個直播間同時在線觀看的人數(shù)不超過 10000 人,當人數(shù)達到上限時,新的觀眾將無法進入直播間,只能等待其他觀眾離開后才有機會進入。
限流的實現(xiàn)方式
限流可以在不同的層次進行實現(xiàn),常見的實現(xiàn)方式包括:
- 應(yīng)用層限流:應(yīng)用層限流是在應(yīng)用程序內(nèi)部實現(xiàn)的限流邏輯,通常可以通過編寫代碼來實現(xiàn)。例如,在 Java 應(yīng)用中,可以使用 Guava 庫中的 RateLimiter 類來實現(xiàn)令牌桶算法的限流功能。在應(yīng)用層實現(xiàn)限流的優(yōu)點是可以根據(jù)業(yè)務(wù)需求進行靈活定制,能夠精確控制每個業(yè)務(wù)模塊的限流策略。但其缺點是如果應(yīng)用程序部署在多個服務(wù)器上,應(yīng)用層限流只能對單個服務(wù)器上的請求進行限制,無法實現(xiàn)全局統(tǒng)一的限流。
- 網(wǎng)關(guān)層限流:網(wǎng)關(guān)作為系統(tǒng)的入口,是進行限流的理想位置。通過在網(wǎng)關(guān)層設(shè)置限流規(guī)則,可以對所有進入系統(tǒng)的請求進行統(tǒng)一的流量控制。常見的網(wǎng)關(guān)軟件如 Nginx、Kong 等都提供了強大的限流功能。例如,Nginx 可以使用 limit_req_zone 指令來實現(xiàn)基于令牌桶算法的速率限流,使用 limit_conn_zone 指令來實現(xiàn)基于并發(fā)連接數(shù)的限流。網(wǎng)關(guān)層限流的優(yōu)點是可以對整個系統(tǒng)的流量進行集中管理和控制,并且可以很方便地對不同的服務(wù)或接口設(shè)置不同的限流策略。同時,由于網(wǎng)關(guān)通常具有較高的性能和并發(fā)處理能力,能夠承受大量的請求流量,因此在網(wǎng)關(guān)層進行限流不會對系統(tǒng)的性能產(chǎn)生較大影響。
- 中間件限流:除了應(yīng)用層和網(wǎng)關(guān)層,還可以利用中間件來實現(xiàn)限流功能。例如,使用 Redis 作為分布式緩存中間件時,可以結(jié)合 Lua 腳本來實現(xiàn)基于 Redis 的限流。通過在 Redis 中維護一個計數(shù)器,每次請求到達時,通過 Lua 腳本原子性地增加計數(shù)器的值,并與限流閾值進行比較,從而實現(xiàn)限流控制。中間件限流的優(yōu)點是可以利用中間。
總結(jié)
這三把利器各有其特點,通常會結(jié)合使用,以達到最佳的效果。例如,可以通過緩存來減少數(shù)據(jù)庫的訪問,通過降級來應(yīng)對系統(tǒng)故障,通過限流來防止系統(tǒng)過載。在設(shè)計高并發(fā)系統(tǒng)時,需要根據(jù)系統(tǒng)的具體需求和特點,合理地使用這些技術(shù)。