Redis常見問題及解決方案

在Redis的運維使用過程當中你遇到過那些問題,又是如何解決的呢?本文收集了一些Redis的常見問題以及解決方案,與你們一同探討。css

碼字不易,歡迎你們轉載,煩請註明出處;謝謝配合html

你的Redis有bigkeys嗎?

什麼是bigkeys

bigkeys是指key不恰當設定,抑或是key對應的value值佔用內存空間過大;具體表現爲如下幾種情形:python

  • key值不恰當設定(比較少見),key設定冗長
  • String類型 value值長度過大
  • Hash,List,Set,Zset 包含元素個數過多

bigkeys有什麼危害

爲何咱們必須警戒bigkey呢?其實bigkey主要有如下幾個方面的危害:redis

  • 內存使用不均勻,例如:在Redis-Cluster模式中,bigkey會形成節點內存使用不均勻。
  • 超時阻塞,因爲Redis是單線程架構,操做bigkey耗時較長,有可能形成Redis阻塞。
  • 網絡擁阻,例如:一個bigkey佔用空間是1M,每秒訪問1000次,將形成1000M的流量,可能形成打滿機器帶寬。

固然,若是bigkey訪問頻率不高,也僅會形成節點間內存使用不均;而當bigkey訪問頻繁時,其帶來的影響是不可想象的,因此平常在開發運維的過程當中應該警戒bigkey的存在。數據庫

如何找到bigkeys

瞭解到bigkey危害,咱們該如何發現bigkeys呢?centos

Redis在設計之初就考慮到bigkeys的問題,咱們可使用 redis-cli --bigkeys 來發現bigkeys的分佈狀況;以後你若是想進一步瞭解bigkeys的具體狀況可使用 debug object <key> 來肯定該key的具體信息。參考如下示例:緩存

利用redis-cli --bigkeys找到bigkey,具體生產環境執行時強烈建議在從節點實行,若是擔憂OPS過高,可使用 -i 0.1 ,表示每100條scan命令休眠0.1秒;其實該命令實現的原理就是利用咱們經常使用的scan + type + strlen/hlen/llen/scard/zcard 命令實現的,具體能夠從redis-cli.c的源碼中探尋。安全

[root@VM_0_16_centos src]# redis-cli -p 6380 --bigkeys # Scanning the entire keyspace to find biggest keys as well as # average sizes per key type. You can use -i 0.1 to sleep 0.1 sec # per 100 SCAN commands (not usually needed). [00.00%] Biggest string found so far 'h' with 1 bytes [00.00%] Biggest string found so far 'hello' with 105 bytes [00.00%] Biggest string found so far 'heml' with 1434 bytes -------- summary ------- Sampled 3 keys in the keyspace! Total key length in bytes is 10 (avg len 3.33) Biggest string found 'html' has 1434 bytes 0 lists with 0 items (00.00% of keys, avg size 0.00) 0 hashs with 0 fields (00.00% of keys, avg size 0.00) 3 strings with 1540 bytes (100.00% of keys, avg size 513.33) 0 streams with 0 entries (00.00% of keys, avg size 0.00) 0 sets with 0 members (00.00% of keys, avg size 0.00) 0 zsets with 0 members (00.00% of keys, avg size 0.00) 

執行結果是發現String類型的"html"爲bigkey,咱們緊接着來了解"html"的具體信息;使用
debug object <key> 命令,還有若是是對於元素個數較多的數據結構,該命令可能會阻塞redis實例,因此強烈建議在從節點執行bash

[root@VM_0_16_centos src]# redis-cli -p 6380 127.0.0.1:6379> debug object html Value at:0x7f0b13a665c0 refcount:1 encoding:raw serializedlength:251 lru:12181323 lru_seconds_idle:229 127.0.0.1:6379> strlen html (integer) 1434 

咱們發現key爲"html"的String類型的value長達1434個字節,以上即是演示查找bigkeys的過程;除了以上方式咱們能夠在bigkeys影響redis正常提供服務以前,經過 scan + debug object 對懷疑的bigkeys進行逐個檢查。網絡

固然你若是擔憂執行相關命令會對正式環境有必定的影響,你也能夠經過對RDB進行備份,而後根據RDB文件的結構,對RDB中的數據進行逐個分析一樣的能夠找到bigkey,不過這種方式的開發成本會有些高;使用者能夠依據本身的實際狀況來酌情判斷。

如何處理bigkeys

通過一番折騰,咱們終於找到bigkeys了,那麼咱們應該如何處理它呢?

在Redis4.0以前版本,因爲DEL命令是同步刪除的,針對String類型的bigkeys確實可使用DEL命令,刪除速度相對較快,通常不會阻塞redis;然而對於元素個數較多的數據結構,使用DEL命令來刪除可能會阻塞redis實例;針對 Hash 結構,咱們能夠利用 HSCAN + HDEL 刪除元素的成員,成員刪除以後再利用 DEL 刪除key;其他數據相似都是漸進的方式先刪除成員,再刪除key。

Redis4.0版本以後則支持了Lazy Delete Free模式,你可使用 UNLINK 命令來刪除bigkeys,它的實現是異步的,具體能夠從redis-cli.c的源碼中探尋,你須要先確認打開了lazyfree相關配置。

bigkeys總結

bigkeys的表現形式是內存分配不均;頻繁操做的實際影響是有可能形成超時阻塞,網絡擁阻;解決思路是事前監控,事中找到bigkeys,並經過正確的方式刪除bigkeys。

你的Redis有hotkeys嗎?

什麼是hotkeys?

hotkeys是在Redis實例中某些key的操做頻次遠高於其餘key,那麼這些被頻繁操做的熱點key咱們就稱之爲hotkeys。

hotkeys有什麼危害?

hotkeys有什麼危害呢?以Redis-Cluster模式爲例,存在hotkeys的節點,將面臨如下挑戰:

  • 請求分配不均,存在hotkeys的節點面臨較大的訪問壓力
  • 緩存擊穿,hotkeys過時時,大量請求將直接導向DB
  • 緩存雪崩,擊垮存在hotkeys的節點,致使不能正常提供服務

如何發現hotkeys呢?

Redis4.0以後客戶端提供了hotkeys發現的相關命令,咱們能夠經過 redis-cli --hotkeys 來發現hotkeys;

Redis4.0以前咱們也能夠經過客戶端,代理端,服務端,機器端等多個方面來發現hotkeys:

  • 在客戶端創建全局字典表,對key和調用次數進行統計;缺點:侵入客戶端
  • 若是你的集羣是經過proxy + redis 的方式搭建的,那你能夠很方便的從代理端對key和調用次數進行監控;缺點:限制代理模式的集羣
  • 在服務端能夠利用 monitor,對服務端接收的請求進行監控;缺點:侵入服務端,在高併發狀況下會使內存暴增,適合短期使用
  • 若是你不想侵入服務端與客戶端,能夠對服務端接收的請求進行抓包,分析以及監控;例如使用ELK(Elasticsearch + Logstach + kinbana)用packetbeat進行抓包。

如何處理hotkeys?

咱們瞭解到hotkeys的危害,並能夠經過技術手段找到hotkeys之後,咱們該怎麼對系統作優化呢?

首先針對hotkeys過時,面臨的重建問題,可使用如下有效手段來儘量的減小key重建的過程:

  • 設置互斥鎖,保證由一個線程完成熱點key的重建,避免大量的請求直接導向DB
  • "永不過時",將hotkeys的過時時間設置較長的時間,或者永不過時;等待hotkeys觸發的熱點事件過去後再考慮過時。

針對Redis集羣的優化,包括但不限於如下幾種方式:

  • hotkeys表現就是請求分配不均;咱們能夠以此爲出發點,來想辦法使請求儘量的分佈平均;例如:利用<hotkeys_n,value> ,n爲隨機數,儘量的多個實例都有該數據,在訪問時在n的範圍內取隨機數以此來分攤請求;此方式須要必定的代碼改造;
  • 本地緩存,此方式須要對熱點信息有預知,例如:電商產品大促,熱點產生在能夠預知的範圍內,即可以考慮此方式;
  • 集羣的熱點數據的節點的擴容,此方式原理同第一種方式相同,不一樣點在於不須要對代碼進行改造,而是直接增長hotkeys對應節點的數據副本,使多個節點都具有提供該數據的讀取能力,以此來均衡請求。

hotkeys總結

hotkeys的表現形式是請求的分配不均,問題惡化將致使Redis集羣請求傾斜,甚至集羣雪崩,咱們能夠經過多種途徑來均衡請求,避免單個節點過熱;若是hotkeys的超時實現太短,可能會致使大量請求涌入到DB,併發重建key,能夠經過合理的鎖機制或者設置合理的超時時間來避免。

Redis緩存穿透

什麼是緩存穿透

緩存穿透是大量請求的key在緩存中沒有,直接請求到DB,使緩存失去保護數據庫的做用;例如:黑客刻意構建大量緩存中沒有的key,致使每次處理請求都須要去訪問數據庫。

正常緩存處理流程

 
緩存穿透處理流程
 
緩存穿透的流程即是故意構建緩存中沒有的key致使,全部的請求必須查庫;緩存失去其保護數據庫的意義。

解決緩存穿透

經過以上流程圖咱們對緩存穿透有了必定的瞭解,那該如何解決此類問題呢?一般解決的方式有兩種:

(1) 對空值進行緩存,設置較短的失效時間;

 

分析:咱們對null進行緩存,Redis須要更大的內存空間;此方案適用於請求key變化不頻繁的狀況;如何黑客惡意攻擊,每次構建的不一樣的請求key,這種方案並不能從根本上解決此問題。

(2) 使用布隆過濾器,布隆過濾器優點在於檢索一個元素是否在一個集合內;咱們能夠利用布隆過濾器來判斷請求的key是否在合理的範圍內,若是不存在,則直接過濾掉。

 

分析:能夠利用Redis的 BitMap來實現布隆過濾器,用其來緩存目標數據集變化不頻繁,而請求key變化頻繁的狀況。

Redis緩存雪崩

什麼是緩存雪崩

緩存雪崩是指因爲緩存集中過時或者緩存不可用,致使大量請求直接導向數據庫。在高併發的狀況下,巨大的請求量有可能致使數據庫的崩潰,甚至致使整個應用體系的全盤崩潰;緩存失去保護是數據庫的做用,而巨大致使流量流向數據庫就是緩存雪崩的表現形式。

如何預防及避免

  • 設置合理的過時策略,避免緩存集中過時。
  • hotkeys分片存儲,避免請求數據的傾斜,致使緩存。
  • hotkeys設置合理的過時時間或者「永不過時」。

Redis阻塞

咱們知道Redis是單線程模型,若是線上Redis發生阻塞對整個應用將是毀滅性的;那什麼緣由會致使Redis阻塞呢?

API或數據結構使用不合理

常見的是在生產上執行時間複雜度高的命令如: KEYS,能夠經過RENAME 方式將命令修改成不易猜想的,避免開發運維人員的不當執行。
數據結構的不合理,如存在頻繁操做bigkeys,有可能形成阻塞,將bigkeys拆分紅成員較小的key。

CPU飽和

Redis單實例OPS能夠到達平均10W+左右,若是你的Redis實例OPS已經達到較高的數值,那你能夠考慮集羣的水平擴展,來下降實例的OPS;可是你的Redis實例OPS不高,CPU使用率較高,那你應該檢查應用是否使用了時間複雜度較高的命令。

持久化阻塞

咱們知道Redis能夠進行持久化來防止數據的丟失;RDB方式,主進程會fork一個共享內存子進程來建立RDB文件,若是fork耗時過長,必然將阻塞主進程。
AOF刷盤,一般咱們設置的刷盤策略是everysec,但因爲磁盤壓力過大,fsync有可能耗時較長,當時間大於1秒時,爲了保證數據安全,下次fsync調用將阻塞知道上次調用結束。

其餘緣由

CPU競爭:Redis是CPU密集型應用,應避免跟其餘CPU密集型應用部署在一塊兒
內存交換:Redis因爲從內存中直接讀取,因此響應速度很快;當內存嚴重不足時,可能會存在內存交換,這將影響Redis的執行效率;經過cat /proc/$pid/smaps | grep Swap 來確認是否有頻繁的內存交換。 網絡問題:鏈接數限制或者網絡延時等也有可能致使阻塞 

Redis淘汰策略

當Redis的內存使用達到限制時(可經過maxmemory <bytes>設置),會根據根據淘汰策略來移除Keys;有以下淘汰策略:

  • allkeys-random:在全部keys中隨機移除
  • allkeys-lru:在全部keys中使用lru移除
  • allkeys-lfu:在全部keys中使用lfu移除
  • volatile-random:在過時keys中隨機移除
  • volatile-lru:在過時keys中使用lru移除
  • volatile-lfu:在過時keys中使用lfu移除
  • volatile-ttl:移除即將過時
  • noevction:不移除任何key,空間不足時將拋出error

lru:Least Recently Used 最近最少使用
lfu:Least Frequently Used 最不常用

總結

本文介紹了bigkeys,hotkeys,緩存穿透,緩存雪崩,阻塞等問題;然而咱們在實際應用中不免會遇到各類各樣的問題,本文難以一一列舉;可是面對問題咱們要沉着冷靜,瞭解清楚問題的現象與本質,找到問題的癥結所在,隨後在對症下藥即可以解決問題。 

相關文章
相關標籤/搜索