溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用redis的要點分析

發(fā)布時間:2021-01-26 11:17:37 來源:億速云 閱讀:154 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章將為大家詳細(xì)講解有關(guān)使用redis的要點分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

一、導(dǎo)語

Redis(Remote Dictionary Server ),即遠(yuǎn)程字典服務(wù),是一個開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API。

由于其上手快,執(zhí)行效率高,擁有多種數(shù)據(jù)結(jié)構(gòu),支持持久化以及集群等功能和特點被眾多互聯(lián)網(wǎng)公司所使用。但是,如果使用和操作不當(dāng),會引起內(nèi)存浪費,甚至系統(tǒng)宕機等嚴(yán)重后果。

二、要點分析

2.1 使用正確的數(shù)據(jù)類型

在 Redis 5 種數(shù)據(jù)類型中,string 類型最為常用,也最為簡單。但是,能解決問題不代表使用了正確的數(shù)據(jù)類型。

例如,將一個用戶(name,age,city)信息保存到 Redis 中,下邊有三種方案:

方案1:使用 string 類型,每個屬性當(dāng)作一個 key

set user:1:name laowang
set user:1:age 40
set user:1:city shanghai

優(yōu)點:簡單直觀,每個屬性支持更新操作
缺點:使用過多的 key,占用的內(nèi)存較大,同時用戶信息的聚合性較差,管理和維護麻煩

方案2:使用 string 類型,將用戶信息序列化成字符串保存

// 序列化用戶信息
String userInfo = serialize(user)
set user:1 userInfo

優(yōu)點:簡化存儲步驟
缺點:序列化和反序列化存在一定開銷

方案3:使用 hash 類型,每個屬性使用一對 field-value,但只用一個 key

hmset user:1 name laowang age 40 city shanghai

優(yōu)點:簡單直觀,合理使用可以減少內(nèi)存空間

總結(jié):盡量減少 Redis 中的 key。

2.2 警惕 Big Key

big key 一般指的是字符串類型 value 值非常大(大于10KB),或哈希、列表、集合、有序集合元素個數(shù)多(大于5000個)的 key。

big key 會對 Redis 造成很多負(fù)面影響:

內(nèi)存不均:在集群環(huán)境下,big key 被分配到某個節(jié)點機器中,由于不知道被分配到哪個節(jié)點上且該節(jié)點內(nèi)存占用大,不利于集群環(huán)境下內(nèi)存的統(tǒng)一管理

超時阻塞:由于 Redis 是單線程操作,操作 big key 比較耗時,容易造成阻塞

過期刪除:big key 不單讀寫慢,刪除也慢,刪除過期 big key 也比較耗時

遷移困難:由于數(shù)據(jù)龐大,備份和還原也容易造成阻塞,操作失敗

知道了 big key 的危害,我們?nèi)绾闻袛嗪筒樵?big key 呢?其實,redis-cli 提供了 --bigkeys 參數(shù),鍵入 redis-cli --bigkeys 即可查詢出 big key 。

找到 big key 后,我們一般會將 big key 拆分成多個小 key 進行存儲。這種做法似乎與 2.1 的總結(jié)相矛盾,但任何方案都有優(yōu)缺點,衡量利弊取決于實際情況。

總結(jié):盡量減少 Redis 中的 big key。

補充:如果想查看某個 key 所占用的內(nèi)存空間,可以使用 memory usage  命令。注意:該命令是 Redis 4.0+ 才開始提供的,如想使用必須將 Redis 升級至 4.0+。

2.3 內(nèi)存消耗

即便我們合適使用正確的數(shù)據(jù)類型保存數(shù)據(jù),將 Big Key 拆分小 key,還是會出現(xiàn)內(nèi)存消耗問題,那么 Redis 內(nèi)存消耗是如何產(chǎn)生的呢?一般由以下 3 種情況產(chǎn)生:

業(yè)務(wù)不斷發(fā)展,存儲的數(shù)據(jù)不斷增多(不可避免)

無效/過期的數(shù)據(jù)沒有及時處理(可優(yōu)化)

沒有對冷數(shù)據(jù)進行降級(可優(yōu)化)

在優(yōu)化情況 2 之前,我們得先知道為什么會出現(xiàn)沒有及時處理過期數(shù)據(jù)的問題,這得說到 Redis 提供的 3 種過期刪除策略:

定時刪除:對于每個設(shè)置了過期時間的 key 都會創(chuàng)建一個定時器,一旦達到過期時間就立即刪除

惰性刪除:當(dāng)訪問一個 key 時,才判斷該 key 是否已過期,如過期就刪除

定期刪除:每隔一段時間掃描 Redis 中過期 key 的字典,并清除部分過期的 key

由于定時刪除需要創(chuàng)建定時器,會占用的大量內(nèi)存,同時精準(zhǔn)刪除大量 key 也會消耗大量 CPU 資源,因此 Redis 同時采用的是惰性刪除和定時刪除兩種策略。如果客戶端沒有請求過期的 key 或定期刪除線程沒有掃描到并清除這個 key,該 key 就會一直占用著內(nèi)存,導(dǎo)致內(nèi)存浪費。

知道了內(nèi)存消耗的原因后,我們可以很快地想出優(yōu)化方案:手動刪除。

當(dāng)使用完緩存后,緩存即使設(shè)置了過期時間,我們也要手動調(diào)用 del  方法/命令刪除。如果不能當(dāng)場刪除,我們也可在代碼中開啟定時器定期刪除這些過期的 key,相比較 Redis 的兩種刪除策略,手動清除數(shù)據(jù)要及時很多。

情況 3 的問題不算大,針對其優(yōu)化的手段,我們可以調(diào)整 Redis 的淘汰策略。

2.4 多命令的執(zhí)行

Redis 是基于一個 request, 一個 response 的同步請求服務(wù)。即當(dāng)多個客戶端向 Redis 服務(wù)端發(fā)送命令時,Redis 服務(wù)端只能接收和處理其中的一個客戶端的命令,其他客戶端只能等待 Redis 服務(wù)端處理好當(dāng)前的命令并作出響應(yīng)后才會繼續(xù)接收和處理其他命令請求。

Redis 處理命令分 3 個過程:接收命令,處理命令,返回結(jié)果。由于處理的數(shù)據(jù)都是在內(nèi)存中的,因此處理時長通常都是納秒級別,非???big key 除外)。因此,大部分耗時的情況都發(fā)生在接受命令和返回結(jié)果上。當(dāng)客戶端發(fā)送多個命令給 Redis 服務(wù)器時,如果有一條命令處理時長很久,其他命令只能等待著,從而影響整體性能。

為了解決這類問題,Redis 提供了 pipeline(管道),客戶端可以將多條命令放入 pipeline 中,然后一次性將 pipeline 的命令發(fā)給 Redis 服務(wù)端處理,當(dāng) Redis 服務(wù)端處理完畢后再一次性將結(jié)果返回給客戶端。這樣處理減少了客戶端與 Redis 服務(wù)端的交互次數(shù),從而減少了往返時間,提升了性能。

補充:

Redis pipeline 與原生批量命令對比:

原生批量命令是原子性,pipeline 是非原子性

原生批量命令一次只能執(zhí)行一種命令,pipeline 支持執(zhí)行多種命令

原生批量命令是服務(wù)端實現(xiàn),pipeline 需要服務(wù)端和客戶端實現(xiàn)

使用 Redis pipeline 的注意事項:

使用 pipeline 裝載的命令數(shù)量不能太多

pipeline 中的命令會按照緩沖的順序執(zhí)行,但是可能會穿插其他客戶端發(fā)來的命令,即不保證時序性

pipeline 執(zhí)行中間某一指令出現(xiàn)異常,會繼續(xù)執(zhí)行后續(xù)的指令,即不保證原子性

2.5 緩存穿透

在項目中運用緩存,我們通常的設(shè)計思路如下圖:

使用redis的要點分析

發(fā)送請求查詢數(shù)據(jù),查詢規(guī)則是先查緩存,如果緩存沒有數(shù)據(jù)再查詢數(shù)據(jù)庫,將查到的數(shù)據(jù)放入緩存最后返回數(shù)據(jù)給客戶端。如果請求的數(shù)據(jù)是不存在的,最終每次請求都會請求到數(shù)據(jù)庫中,這就是緩存穿透。

緩存穿透存到很大的安全隱患,如果有人使用工具發(fā)送大量請求,請求一個不存在的數(shù)據(jù),大量請求會流入到數(shù)據(jù)庫上,導(dǎo)致數(shù)據(jù)庫壓力增大,可能會導(dǎo)致數(shù)據(jù)庫宕機,進而影響整個應(yīng)用的正常運行,導(dǎo)致系統(tǒng)癱瘓。

解決這類問題,重點在于減少對數(shù)據(jù)庫的訪問,通常有以下幾種方案:

緩存預(yù)熱:系統(tǒng)發(fā)布上線后,提前把相關(guān)的數(shù)據(jù)直接加載到緩存系統(tǒng)中

設(shè)置默認(rèn)值:如果請求最終落在數(shù)據(jù)庫中,數(shù)據(jù)庫也查不出數(shù)據(jù),給緩存 key 設(shè)置一個默認(rèn)值,放入緩存中,注意:由于這個默認(rèn)值是無意義的,因此我們需要設(shè)置過期時間,減少內(nèi)存占用

布隆過濾器:將所有可能存在的數(shù)據(jù)哈希到一個足夠大的 bitmap 中,一個不存在的數(shù)據(jù)肯定會被 bitmap 攔截掉

2.6 緩存雪崩

緩存雪崩: 簡單來說是指大量請求訪問緩存數(shù)據(jù)但無法查詢到,進而去請求數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫壓力增大,性能下降,不堪重負(fù)宕機,從而影響整個系統(tǒng)正常運行,甚至系統(tǒng)癱瘓的現(xiàn)象。

比如,一個完整的系統(tǒng)由系統(tǒng)A,系統(tǒng)B,系統(tǒng)C 三個子系統(tǒng)組成,它們的數(shù)據(jù)請求鏈?zhǔn)窍到y(tǒng)A -> 系統(tǒng)B -> 系統(tǒng)C -> 數(shù)據(jù)庫。如果緩存中沒有數(shù)據(jù),數(shù)據(jù)庫宕機,系統(tǒng)C不能查詢數(shù)據(jù)作出響應(yīng),只能處在重試等待的階段,從而影響了系統(tǒng)B 和系統(tǒng)A。一處節(jié)點發(fā)生異常導(dǎo)致一連串的問題就像雪山的一陣風(fēng)吹過引起雪崩的現(xiàn)象。

看到這里,可能有讀者會疑惑,緩存穿透和緩存雪崩有什么區(qū)別呢?

緩存穿透側(cè)重于請求的數(shù)據(jù)不在緩存中,從而去請求數(shù)據(jù)庫,就好像直接透過緩存直接請求數(shù)據(jù)庫。

緩存雪崩側(cè)重于大請求由于在緩存中查詢不出數(shù)據(jù),從而訪問數(shù)據(jù)庫導(dǎo)致數(shù)據(jù)庫壓力增大引起一系列異常。

要解決緩存雪崩問題,還是得先知道導(dǎo)致問題的原因:

Redis 自身出現(xiàn)問題

熱點數(shù)據(jù)集中失效

針對原因1,我們可以做主從,集群,盡量讓請求都在緩存中查到數(shù)據(jù),減少對數(shù)據(jù)庫的訪問

針對原因2,給緩存設(shè)置過期時間時,錯開過期時間(如在基礎(chǔ)時間上在增減一個隨機值),避免緩存集中失效。同時,我們還可以設(shè)置本地緩存(如 ehcache),對接口進行限流或服務(wù)降級,也可以減少數(shù)據(jù)庫的訪問壓力。

關(guān)于“使用redis的要點分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI