在Redis的運維使用過程當中你遇到過那些問題,又是如何解決的呢?本文收集了一些Redis的常見問題以及解決方案,與你們一同探討。css
碼字不易,歡迎你們轉載,煩請註明出處;謝謝配合html
bigkeys是指key不恰當設定,抑或是key對應的value值佔用內存空間過大;具體表現爲如下幾種情形:python
爲何咱們必須警戒bigkey呢?其實bigkey主要有如下幾個方面的危害:redis
固然,若是bigkey訪問頻率不高,也僅會形成節點間內存使用不均;而當bigkey訪問頻繁時,其帶來的影響是不可想象的,因此平常在開發運維的過程當中應該警戒bigkey的存在。數據庫
瞭解到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了,那麼咱們應該如何處理它呢?
在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。
hotkeys是在Redis實例中某些key的操做頻次遠高於其餘key,那麼這些被頻繁操做的熱點key咱們就稱之爲hotkeys。
hotkeys有什麼危害呢?以Redis-Cluster模式爲例,存在hotkeys的節點,將面臨如下挑戰:
Redis4.0以後客戶端提供了hotkeys發現的相關命令,咱們能夠經過 redis-cli --hotkeys 來發現hotkeys;
Redis4.0以前咱們也能夠經過客戶端,代理端,服務端,機器端等多個方面來發現hotkeys:
咱們瞭解到hotkeys的危害,並能夠經過技術手段找到hotkeys之後,咱們該怎麼對系統作優化呢?
首先針對hotkeys過時,面臨的重建問題,可使用如下有效手段來儘量的減小key重建的過程:
針對Redis集羣的優化,包括但不限於如下幾種方式:
hotkeys的表現形式是請求的分配不均,問題惡化將致使Redis集羣請求傾斜,甚至集羣雪崩,咱們能夠經過多種途徑來均衡請求,避免單個節點過熱;若是hotkeys的超時實現太短,可能會致使大量請求涌入到DB,併發重建key,能夠經過合理的鎖機制或者設置合理的超時時間來避免。
緩存穿透是大量請求的key在緩存中沒有,直接請求到DB,使緩存失去保護數據庫的做用;例如:黑客刻意構建大量緩存中沒有的key,致使每次處理請求都須要去訪問數據庫。
正常緩存處理流程
經過以上流程圖咱們對緩存穿透有了必定的瞭解,那該如何解決此類問題呢?一般解決的方式有兩種:
(1) 對空值進行緩存,設置較短的失效時間;
分析:咱們對null進行緩存,Redis須要更大的內存空間;此方案適用於請求key變化不頻繁的狀況;如何黑客惡意攻擊,每次構建的不一樣的請求key,這種方案並不能從根本上解決此問題。
(2) 使用布隆過濾器,布隆過濾器優點在於檢索一個元素是否在一個集合內;咱們能夠利用布隆過濾器來判斷請求的key是否在合理的範圍內,若是不存在,則直接過濾掉。
分析:能夠利用Redis的 BitMap來實現布隆過濾器,用其來緩存目標數據集變化不頻繁,而請求key變化頻繁的狀況。
緩存雪崩是指因爲緩存集中過時或者緩存不可用,致使大量請求直接導向數據庫。在高併發的狀況下,巨大的請求量有可能致使數據庫的崩潰,甚至致使整個應用體系的全盤崩潰;緩存失去保護是數據庫的做用,而巨大致使流量流向數據庫就是緩存雪崩的表現形式。
咱們知道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的內存使用達到限制時(可經過maxmemory <bytes>設置),會根據根據淘汰策略來移除Keys;有以下淘汰策略:
lru:Least Recently Used 最近最少使用
lfu:Least Frequently Used 最不常用
本文介紹了bigkeys,hotkeys,緩存穿透,緩存雪崩,阻塞等問題;然而咱們在實際應用中不免會遇到各類各樣的問題,本文難以一一列舉;可是面對問題咱們要沉着冷靜,瞭解清楚問題的現象與本質,找到問題的癥結所在,隨後在對症下藥即可以解決問題。