您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關使用redis的要點分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
一、導語
Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API。
由于其上手快,執行效率高,擁有多種數據結構,支持持久化以及集群等功能和特點被眾多互聯網公司所使用。但是,如果使用和操作不當,會引起內存浪費,甚至系統宕機等嚴重后果。
二、要點分析
2.1 使用正確的數據類型
在 Redis 5 種數據類型中,string 類型最為常用,也最為簡單。但是,能解決問題不代表使用了正確的數據類型。
例如,將一個用戶(name,age,city)信息保存到 Redis 中,下邊有三種方案:
方案1:使用 string 類型,每個屬性當作一個 key
set user:1:name laowang set user:1:age 40 set user:1:city shanghai
優點:簡單直觀,每個屬性支持更新操作
缺點:使用過多的 key,占用的內存較大,同時用戶信息的聚合性較差,管理和維護麻煩
方案2:使用 string 類型,將用戶信息序列化成字符串保存
// 序列化用戶信息 String userInfo = serialize(user) set user:1 userInfo
優點:簡化存儲步驟
缺點:序列化和反序列化存在一定開銷
方案3:使用 hash 類型,每個屬性使用一對 field-value,但只用一個 key
hmset user:1 name laowang age 40 city shanghai
優點:簡單直觀,合理使用可以減少內存空間
總結:盡量減少 Redis 中的 key。
2.2 警惕 Big Key
big key 一般指的是字符串類型 value 值非常大(大于10KB),或哈希、列表、集合、有序集合元素個數多(大于5000個)的 key。
big key 會對 Redis 造成很多負面影響:
內存不均:在集群環境下,big key 被分配到某個節點機器中,由于不知道被分配到哪個節點上且該節點內存占用大,不利于集群環境下內存的統一管理
超時阻塞:由于 Redis 是單線程操作,操作 big key 比較耗時,容易造成阻塞
過期刪除:big key 不單讀寫慢,刪除也慢,刪除過期 big key 也比較耗時
遷移困難:由于數據龐大,備份和還原也容易造成阻塞,操作失敗
知道了 big key 的危害,我們如何判斷和查詢 big key 呢?其實,redis-cli 提供了 --bigkeys 參數,鍵入 redis-cli --bigkeys 即可查詢出 big key 。
找到 big key 后,我們一般會將 big key 拆分成多個小 key 進行存儲。這種做法似乎與 2.1 的總結相矛盾,但任何方案都有優缺點,衡量利弊取決于實際情況。
總結:盡量減少 Redis 中的 big key。
補充:如果想查看某個 key 所占用的內存空間,可以使用 memory usage 命令。注意:該命令是 Redis 4.0+ 才開始提供的,如想使用必須將 Redis 升級至 4.0+。
2.3 內存消耗
即便我們合適使用正確的數據類型保存數據,將 Big Key 拆分小 key,還是會出現內存消耗問題,那么 Redis 內存消耗是如何產生的呢?一般由以下 3 種情況產生:
業務不斷發展,存儲的數據不斷增多(不可避免)
無效/過期的數據沒有及時處理(可優化)
沒有對冷數據進行降級(可優化)
在優化情況 2 之前,我們得先知道為什么會出現沒有及時處理過期數據的問題,這得說到 Redis 提供的 3 種過期刪除策略:
定時刪除:對于每個設置了過期時間的 key 都會創建一個定時器,一旦達到過期時間就立即刪除
惰性刪除:當訪問一個 key 時,才判斷該 key 是否已過期,如過期就刪除
定期刪除:每隔一段時間掃描 Redis 中過期 key 的字典,并清除部分過期的 key
由于定時刪除需要創建定時器,會占用的大量內存,同時精準刪除大量 key 也會消耗大量 CPU 資源,因此 Redis 同時采用的是惰性刪除和定時刪除兩種策略。如果客戶端沒有請求過期的 key 或定期刪除線程沒有掃描到并清除這個 key,該 key 就會一直占用著內存,導致內存浪費。
知道了內存消耗的原因后,我們可以很快地想出優化方案:手動刪除。
當使用完緩存后,緩存即使設置了過期時間,我們也要手動調用 del 方法/命令刪除。如果不能當場刪除,我們也可在代碼中開啟定時器定期刪除這些過期的 key,相比較 Redis 的兩種刪除策略,手動清除數據要及時很多。
情況 3 的問題不算大,針對其優化的手段,我們可以調整 Redis 的淘汰策略。
2.4 多命令的執行
Redis 是基于一個 request, 一個 response 的同步請求服務。即當多個客戶端向 Redis 服務端發送命令時,Redis 服務端只能接收和處理其中的一個客戶端的命令,其他客戶端只能等待 Redis 服務端處理好當前的命令并作出響應后才會繼續接收和處理其他命令請求。
Redis 處理命令分 3 個過程:接收命令,處理命令,返回結果。由于處理的數據都是在內存中的,因此處理時長通常都是納秒級別,非常快(big key 除外)。因此,大部分耗時的情況都發生在接受命令和返回結果上。當客戶端發送多個命令給 Redis 服務器時,如果有一條命令處理時長很久,其他命令只能等待著,從而影響整體性能。
為了解決這類問題,Redis 提供了 pipeline(管道),客戶端可以將多條命令放入 pipeline 中,然后一次性將 pipeline 的命令發給 Redis 服務端處理,當 Redis 服務端處理完畢后再一次性將結果返回給客戶端。這樣處理減少了客戶端與 Redis 服務端的交互次數,從而減少了往返時間,提升了性能。
補充:
Redis pipeline 與原生批量命令對比:
原生批量命令是原子性,pipeline 是非原子性
原生批量命令一次只能執行一種命令,pipeline 支持執行多種命令
原生批量命令是服務端實現,pipeline 需要服務端和客戶端實現
使用 Redis pipeline 的注意事項:
使用 pipeline 裝載的命令數量不能太多
pipeline 中的命令會按照緩沖的順序執行,但是可能會穿插其他客戶端發來的命令,即不保證時序性
pipeline 執行中間某一指令出現異常,會繼續執行后續的指令,即不保證原子性
2.5 緩存穿透
在項目中運用緩存,我們通常的設計思路如下圖:
發送請求查詢數據,查詢規則是先查緩存,如果緩存沒有數據再查詢數據庫,將查到的數據放入緩存最后返回數據給客戶端。如果請求的數據是不存在的,最終每次請求都會請求到數據庫中,這就是緩存穿透。
緩存穿透存到很大的安全隱患,如果有人使用工具發送大量請求,請求一個不存在的數據,大量請求會流入到數據庫上,導致數據庫壓力增大,可能會導致數據庫宕機,進而影響整個應用的正常運行,導致系統癱瘓。
解決這類問題,重點在于減少對數據庫的訪問,通常有以下幾種方案:
緩存預熱:系統發布上線后,提前把相關的數據直接加載到緩存系統中
設置默認值:如果請求最終落在數據庫中,數據庫也查不出數據,給緩存 key 設置一個默認值,放入緩存中,注意:由于這個默認值是無意義的,因此我們需要設置過期時間,減少內存占用
布隆過濾器:將所有可能存在的數據哈希到一個足夠大的 bitmap 中,一個不存在的數據肯定會被 bitmap 攔截掉
2.6 緩存雪崩
緩存雪崩: 簡單來說是指大量請求訪問緩存數據但無法查詢到,進而去請求數據庫,導致數據庫壓力增大,性能下降,不堪重負宕機,從而影響整個系統正常運行,甚至系統癱瘓的現象。
比如,一個完整的系統由系統A,系統B,系統C 三個子系統組成,它們的數據請求鏈是系統A -> 系統B -> 系統C -> 數據庫。如果緩存中沒有數據,數據庫宕機,系統C不能查詢數據作出響應,只能處在重試等待的階段,從而影響了系統B 和系統A。一處節點發生異常導致一連串的問題就像雪山的一陣風吹過引起雪崩的現象。
看到這里,可能有讀者會疑惑,緩存穿透和緩存雪崩有什么區別呢?
緩存穿透側重于請求的數據不在緩存中,從而去請求數據庫,就好像直接透過緩存直接請求數據庫。
緩存雪崩側重于大請求由于在緩存中查詢不出數據,從而訪問數據庫導致數據庫壓力增大引起一系列異常。
要解決緩存雪崩問題,還是得先知道導致問題的原因:
Redis 自身出現問題
熱點數據集中失效
針對原因1,我們可以做主從,集群,盡量讓請求都在緩存中查到數據,減少對數據庫的訪問
針對原因2,給緩存設置過期時間時,錯開過期時間(如在基礎時間上在增減一個隨機值),避免緩存集中失效。同時,我們還可以設置本地緩存(如 ehcache),對接口進行限流或服務降級,也可以減少數據庫的訪問壓力。
關于“使用redis的要點分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。