你遇到過哪些Redis的問題绑榴?

在Redis的運維使用過程中你遇到過那些問題搬男,又是如何解決的呢?本文收集了一些Redis的常見問題以及解決方案彭沼,與大家一同探討缔逛。

碼字不易,歡迎大家轉(zhuǎn)載,煩請注明出處褐奴;謝謝配合

你的Redis有bigkeys嗎按脚?

什么是bigkeys

bigkeys是指key不恰當設(shè)定,抑或是key對應(yīng)的value值占用內(nèi)存空間過大敦冬;具體表現(xiàn)為以下幾種情形:

  • key值不恰當設(shè)定(比較少見)辅搬,key設(shè)定冗長
  • String類型 value值長度過大
  • Hash,List脖旱,Set堪遂,Zset 包含元素個數(shù)過多

bigkeys有什么危害

為什么我們必須警惕bigkey呢?其實bigkey主要有以下幾個方面的危害:

  • 內(nèi)存使用不均勻萌庆,例如:在Redis-Cluster模式中溶褪,bigkey會造成節(jié)點內(nèi)存使用不均勻。
  • 超時阻塞践险,由于Redis是單線程架構(gòu)猿妈,操作bigkey耗時較長,有可能造成Redis阻塞巍虫。
  • 網(wǎng)絡(luò)擁阻彭则,例如:一個bigkey占用空間是1M,每秒訪問1000次占遥,將造成1000M的流量俯抖,可能造成打滿機器帶寬。

當然瓦胎,如果bigkey訪問頻率不高蚌成,也僅會造成節(jié)點間內(nèi)存使用不均;而當bigkey訪問頻繁時凛捏,其帶來的影響是不可想象的担忧,所以日常在開發(fā)運維的過程中應(yīng)該警惕bigkey的存在。

如何找到bigkeys

了解到bigkey危害坯癣,我們該如何發(fā)現(xiàn)bigkeys呢瓶盛?

Redis在設(shè)計之初就考慮到bigkeys的問題,我們可以使用 redis-cli --bigkeys 來發(fā)現(xiàn)bigkeys的分布情況示罗;之后你如果想進一步了解bigkeys的具體情況可以使用 debug object <key> 來確定該key的具體信息惩猫。參考以下示例:

利用redis-cli --bigkeys找到bigkey,具體生產(chǎn)環(huán)境執(zhí)行時強烈建議在從節(jié)點實行蚜点,如果擔心OPS太高轧房,可以使用 -i 0.1 ,表示每100條scan命令休眠0.1秒绍绘;其實該命令實現(xiàn)的原理就是利用我們常用的scan + type + strlen/hlen/llen/scard/zcard 命令實現(xiàn)的奶镶,具體可以從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)

執(zhí)行結(jié)果是發(fā)現(xiàn)String類型的"html"為bigkey,我們緊接著來了解"html"的具體信息厂镇;使用
debug object <key> 命令纤壁,還有如果是對于元素個數(shù)較多的數(shù)據(jù)結(jié)構(gòu),該命令可能會阻塞redis實例捺信,所以強烈建議在從節(jié)點執(zhí)行

[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

我們發(fā)現(xiàn)key為"html"的String類型的value長達1434個字節(jié)酌媒,以上便是演示查找bigkeys的過程;除了以上方式我們可以在bigkeys影響redis正常提供服務(wù)之前迄靠,通過 scan + debug object 對懷疑的bigkeys進行逐個檢查秒咨。

當然你如果擔心執(zhí)行相關(guān)命令會對正式環(huán)境有一定的影響,你也可以通過對RDB進行備份掌挚,然后根據(jù)RDB文件的結(jié)構(gòu)雨席,對RDB中的數(shù)據(jù)進行逐個分析同樣的可以找到bigkey,不過這種方式的開發(fā)成本會有些高疫诽;使用者可以依據(jù)自己的實際情況來酌情判斷。

如何處理bigkeys

經(jīng)過一番折騰旦委,我們終于找到bigkeys了奇徒,那么我們應(yīng)該如何處理它呢?

在Redis4.0之前版本缨硝,由于DEL命令是同步刪除的摩钙,針對String類型的bigkeys確實可以使用DEL命令,刪除速度相對較快查辩,一般不會阻塞redis胖笛;然而對于元素個數(shù)較多的數(shù)據(jù)結(jié)構(gòu),使用DEL命令來刪除可能會阻塞redis實例宜岛;針對 Hash 結(jié)構(gòu)长踊,我們可以利用 HSCAN + HDEL 刪除元素的成員,成員刪除之后再利用 DEL 刪除key萍倡;其余數(shù)據(jù)類似都是漸進的方式先刪除成員身弊,再刪除key。

Redis4.0版本之后則支持了Lazy Delete Free模式列敲,你可以使用 UNLINK 命令來刪除bigkeys阱佛,它的實現(xiàn)是異步的,具體可以從redis-cli.c的源碼中探尋戴而,你需要先確認打開了lazyfree相關(guān)配置凑术。

bigkeys總結(jié)

bigkeys的表現(xiàn)形式是內(nèi)存分配不均;頻繁操作的實際影響是有可能造成超時阻塞所意,網(wǎng)絡(luò)擁阻淮逊;解決思路是事前監(jiān)控催首,事中找到bigkeys,并通過正確的方式刪除bigkeys壮莹。

你的Redis有hotkeys嗎翅帜?

什么是hotkeys?

hotkeys是在Redis實例中某些key的操作頻次遠高于其他key命满,那么這些被頻繁操作的熱點key我們就稱之為hotkeys涝滴。

hotkeys有什么危害?

hotkeys有什么危害呢胶台?以Redis-Cluster模式為例歼疮,存在hotkeys的節(jié)點,將面臨以下挑戰(zhàn):

  • 請求分配不均诈唬,存在hotkeys的節(jié)點面臨較大的訪問壓力
  • 緩存擊穿韩脏,hotkeys過期時,大量請求將直接導(dǎo)向DB
  • 緩存雪崩铸磅,擊垮存在hotkeys的節(jié)點赡矢,導(dǎo)致不能正常提供服務(wù)

如何發(fā)現(xiàn)hotkeys呢?

Redis4.0之后客戶端提供了hotkeys發(fā)現(xiàn)的相關(guān)命令阅仔,我們可以通過 redis-cli --hotkeys 來發(fā)現(xiàn)hotkeys吹散;

Redis4.0之前我們也可以通過客戶端,代理端八酒,服務(wù)端空民,機器端等多個方面來發(fā)現(xiàn)hotkeys:

  • 在客戶端建立全局字典表,對key和調(diào)用次數(shù)進行統(tǒng)計羞迷;缺點:侵入客戶端
  • 如果你的集群是通過proxy + redis 的方式搭建的界轩,那你可以很方便的從代理端對key和調(diào)用次數(shù)進行監(jiān)控;缺點:限制代理模式的集群
  • 在服務(wù)端可以利用 monitor衔瓮,對服務(wù)端接收的請求進行監(jiān)控浊猾;缺點:侵入服務(wù)端,在高并發(fā)情況下會使內(nèi)存暴增热鞍,適合短時間使用
  • 如果你不想侵入服務(wù)端與客戶端与殃,可以對服務(wù)端接收的請求進行抓包,分析以及監(jiān)控碍现;例如使用ELK(Elasticsearch + Logstach + kinbana)用packetbeat進行抓包幅疼。

如何處理hotkeys?

我們了解到hotkeys的危害昼接,并可以通過技術(shù)手段找到hotkeys以后爽篷,我們該怎么對系統(tǒng)做優(yōu)化呢?

首先針對hotkeys過期慢睡,面臨的重建問題逐工,可以使用以下有效手段來盡可能的減少key重建的過程:

  • 設(shè)置互斥鎖铡溪,保證由一個線程完成熱點key的重建,避免大量的請求直接導(dǎo)向DB
  • "永不過期"泪喊,將hotkeys的過期時間設(shè)置較長的時間棕硫,或者永不過期;等待hotkeys觸發(fā)的熱點事件過去后再考慮過期袒啼。

針對Redis集群的優(yōu)化哈扮,包括但不限于以下幾種方式:

  • hotkeys表現(xiàn)就是請求分配不均;我們可以以此為出發(fā)點蚓再,來想辦法使請求盡可能的分布平均滑肉;例如:利用<hotkeys_n,value> ,n為隨機數(shù),盡可能的多個實例都有該數(shù)據(jù)摘仅,在訪問時在n的范圍內(nèi)取隨機數(shù)以此來分攤請求靶庙;此方式需要一定的代碼改造;
  • 本地緩存娃属,此方式需要對熱點信息有預(yù)知六荒,例如:電商產(chǎn)品大促,熱點產(chǎn)生在可以預(yù)知的范圍內(nèi)矾端,便可以考慮此方式掏击;
  • 集群的熱點數(shù)據(jù)的節(jié)點的擴容,此方式原理同第一種方式相同须床,不同點在于不需要對代碼進行改造铐料,而是直接增加hotkeys對應(yīng)節(jié)點的數(shù)據(jù)副本渐裂,使多個節(jié)點都具備提供該數(shù)據(jù)的讀取能力豺旬,以此來均衡請求。

hotkeys總結(jié)

hotkeys的表現(xiàn)形式是請求的分配不均柒凉,問題惡化將導(dǎo)致Redis集群請求傾斜族阅,甚至集群雪崩,我們可以通過多種途徑來均衡請求膝捞,避免單個節(jié)點過熱坦刀;如果hotkeys的超時實現(xiàn)過短,可能會導(dǎo)致大量請求涌入到DB蔬咬,并發(fā)重建key鲤遥,可以通過合理的鎖機制或者設(shè)置合理的超時時間來避免。

Redis緩存穿透

什么是緩存穿透

緩存穿透是大量請求的key在緩存中沒有林艘,直接請求到DB盖奈,使緩存失去保護數(shù)據(jù)庫的作用;例如:黑客刻意構(gòu)建大量緩存中沒有的key狐援,導(dǎo)致每次處理請求都需要去訪問數(shù)據(jù)庫钢坦。

正常緩存處理流程

正常緩存流程.png

緩存穿透處理流程

緩存穿透.png

緩存穿透的流程便是故意構(gòu)建緩存中沒有的key導(dǎo)致究孕,所有的請求必須查庫;緩存失去其保護數(shù)據(jù)庫的意義爹凹。

解決緩存穿透

通過以上流程圖我們對緩存穿透有了一定的了解厨诸,那該如何解決此類問題呢?通常解決的方式有兩種:

(1) 對空值進行緩存禾酱,設(shè)置較短的失效時間微酬;

緩存空結(jié)果.png

分析:我們對null進行緩存,Redis需要更大的內(nèi)存空間宇植;此方案適用于請求key變化不頻繁的情況得封;如何黑客惡意攻擊,每次構(gòu)建的不同的請求key指郁,這種方案并不能從根本上解決此問題忙上。

(2) 使用布隆過濾器,布隆過濾器優(yōu)勢在于檢索一個元素是否在一個集合內(nèi)闲坎;我們可以利用布隆過濾器來判斷請求的key是否在合理的范圍內(nèi)纷纫,如果不存在,則直接過濾掉吧寺。

布隆過濾器.png

分析:可以利用Redis的 BitMap來實現(xiàn)布隆過濾器隅津,用其來緩存目標數(shù)據(jù)集變化不頻繁,而請求key變化頻繁的情況绣溜。

Redis緩存雪崩

什么是緩存雪崩

緩存雪崩是指由于緩存集中過期或者緩存不可用慷彤,導(dǎo)致大量請求直接導(dǎo)向數(shù)據(jù)庫。在高并發(fā)的情況下怖喻,巨大的請求量有可能導(dǎo)致數(shù)據(jù)庫的崩潰底哗,甚至導(dǎo)致整個應(yīng)用體系的全盤崩潰;緩存失去保護是數(shù)據(jù)庫的作用锚沸,而巨大導(dǎo)致流量流向數(shù)據(jù)庫就是緩存雪崩的表現(xiàn)形式跋选。

如何預(yù)防及避免

  • 設(shè)置合理的過期策略,避免緩存集中過期哗蜈。
  • hotkeys分片存儲前标,避免請求數(shù)據(jù)的傾斜,導(dǎo)致緩存距潘。
  • hotkeys設(shè)置合理的過期時間或者“永不過期”炼列。

Redis阻塞

我們知道Redis是單線程模型,如果線上Redis發(fā)生阻塞對整個應(yīng)用將是毀滅性的音比;那什么原因會導(dǎo)致Redis阻塞呢俭尖?

API或數(shù)據(jù)結(jié)構(gòu)使用不合理

常見的是在生產(chǎn)上執(zhí)行時間復(fù)雜度高的命令如: KEYS,可以通過RENAME 方式將命令修改為不易猜測的硅确,避免開發(fā)運維人員的不當執(zhí)行目溉。
數(shù)據(jù)結(jié)構(gòu)的不合理明肮,如存在頻繁操作bigkeys,有可能造成阻塞缭付,將bigkeys拆分成成員較小的key柿估。

CPU飽和

Redis單實例OPS可以到達平均10W+左右,如果你的Redis實例OPS已經(jīng)達到較高的數(shù)值陷猫,那你可以考慮集群的水平擴展秫舌,來降低實例的OPS;但是你的Redis實例OPS不高绣檬,CPU使用率較高足陨,那你應(yīng)該檢查應(yīng)用是否使用了時間復(fù)雜度較高的命令。 

持久化阻塞

我們知道Redis可以進行持久化來防止數(shù)據(jù)的丟失娇未;RDB方式墨缘,主進程會fork一個共享內(nèi)存子進程來創(chuàng)建RDB文件,如果fork耗時過長零抬,必然將阻塞主進程镊讼。
AOF刷盤,通常我們設(shè)置的刷盤策略是everysec平夜,但由于磁盤壓力過大蝶棋,fsync有可能耗時較長,當時間大于1秒時忽妒,為了保證數(shù)據(jù)安全玩裙,下次fsync調(diào)用將阻塞知道上次調(diào)用結(jié)束。

其他原因

CPU競爭:Redis是CPU密集型應(yīng)用段直,應(yīng)避免跟其他CPU密集型應(yīng)用部署在一起
內(nèi)存交換:Redis由于從內(nèi)存中直接讀取吃溅,所以響應(yīng)速度很快;當內(nèi)存嚴重不足時坷牛,可能會存在內(nèi)存交換罕偎,這將影響Redis的執(zhí)行效率很澄;通過cat /proc/$pid/smaps | grep Swap 來確認是否有頻繁的內(nèi)存交換京闰。
網(wǎng)絡(luò)問題:連接數(shù)限制或者網(wǎng)絡(luò)延時等也有可能導(dǎo)致阻塞

Redis淘汰策略

當Redis的內(nèi)存使用達到限制時(可通過maxmemory <bytes>設(shè)置),會根據(jù)根據(jù)淘汰策略來移除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 最不經(jīng)常使用

總結(jié)

本文介紹了bigkeys,hotkeys,緩存穿透,緩存雪崩讯蒲,阻塞等問題痊土;然而我們在實際應(yīng)用中難免會遇到各種各樣的問題,本文難以一一列舉墨林;但是面對問題我們要沉著冷靜赁酝,了解清楚問題的現(xiàn)象與本質(zhì)犯祠,找到問題的癥結(jié)所在,隨后在對癥下藥便可以解決問題酌呆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衡载,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子隙袁,更是在濱河造成了極大的恐慌痰娱,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菩收,死亡現(xiàn)場離奇詭異梨睁,居然都是意外死亡,警方通過查閱死者的電腦和手機娜饵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門坡贺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人箱舞,你說我怎么就攤上這事拴念。” “怎么了褐缠?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵政鼠,是天一觀的道長。 經(jīng)常有香客問我队魏,道長公般,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任胡桨,我火速辦了婚禮官帘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昧谊。我一直安慰自己刽虹,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布呢诬。 她就那樣靜靜地躺著涌哲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尚镰。 梳的紋絲不亂的頭發(fā)上阀圾,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音狗唉,去河邊找鬼初烘。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的肾筐。 我是一名探鬼主播哆料,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吗铐!你這毒婦竟也來了剧劝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤抓歼,失蹤者是張志新(化名)和其女友劉穎讥此,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谣妻,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡萄喳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蹋半。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片他巨。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖减江,靈堂內(nèi)的尸體忽然破棺而出染突,到底是詐尸還是另有隱情,我是刑警寧澤辈灼,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布份企,位于F島的核電站,受9級特大地震影響巡莹,放射性物質(zhì)發(fā)生泄漏司志。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一降宅、第九天 我趴在偏房一處隱蔽的房頂上張望骂远。 院中可真熱鬧,春花似錦腰根、人聲如沸激才。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘸恼。三九已至,卻和暖如春岩睁,著一層夾襖步出監(jiān)牢的瞬間钞脂,已是汗流浹背揣云。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工捕儒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓刘莹,卻偏偏與公主長得像阎毅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子点弯,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容