Redis 中大 Key 與熱 Key 的解決方案
在工作中Redis已經(jīng)成為必備的一款高性能的緩存數(shù)據(jù)庫(kù),但是在實(shí)際的使用過(guò)程中,我們常常會(huì)遇到兩個(gè)常見(jiàn)的問(wèn)題,也就是文章標(biāo)題所說(shuō)的大 key與熱 key。
一、定義
1.什么是大key
大 key 指的是一個(gè)鍵中包含了大量的數(shù)據(jù)。(總結(jié)一個(gè)字就是大)
- 占用空間:大key 通常指的是一個(gè)鍵包含了大量的數(shù)據(jù),使得該鍵對(duì)應(yīng)值的占用的內(nèi)存超出了正常范圍。這個(gè)大小的閾值并不是固定的,而是相對(duì)于 Redis 實(shí)例的可用內(nèi)存而言。當(dāng)一個(gè)鍵的大小超出了 Redis 實(shí)例可用內(nèi)存時(shí),就可以認(rèn)為它是一個(gè)大key。
- 操作耗時(shí):如果對(duì)一個(gè) key 的操作所需的時(shí)間過(guò)長(zhǎng),導(dǎo)致性能下降或者影響其他請(qǐng)求的處理速度,也可以說(shuō)這個(gè) key 是 大key 。因?yàn)檫@種情況通常是由于該 key 下包含了大量的數(shù)據(jù)。
2.什么是熱key
熱 key 指的是頻繁訪問(wèn)的鍵。(總結(jié)就是熱,訪問(wèn)頻繁。)
- 頻繁訪問(wèn):在某一段時(shí)間內(nèi)被頻繁訪問(wèn)的 key 就是 熱key 。
- 業(yè)務(wù)方面:比如商城促銷(xiāo)的場(chǎng)景下,某個(gè)商品的緩存可能就會(huì)成為 熱key。這種情況下 熱key 反應(yīng)的不僅是該鍵的訪問(wèn)頻率高,還反映了用戶對(duì)某個(gè)業(yè)務(wù)功能的熱度。
- 性能方面:熱key 的頻繁訪問(wèn)造成 Redis 的 CPU 占用率過(guò)高,造成響應(yīng)時(shí)間延長(zhǎng)或者請(qǐng)求阻塞,從而造成系統(tǒng)崩潰。
key 的大與不大,熱與不熱要根據(jù)自己的業(yè)務(wù),從實(shí)際情況進(jìn)行評(píng)估。
二、影響
1.大 key 的影響
- 內(nèi)存消耗:在進(jìn)行緩存時(shí)降低緩存的效率,占用大量的內(nèi)存空間,使得 Redis 的內(nèi)存消耗急劇增加,還可能導(dǎo)致 Redis 實(shí)例的內(nèi)存資源不足,甚至出發(fā)內(nèi)存淘汰策略,從而影響系統(tǒng)的正常運(yùn)行。
- 性能下降:處理大的 key,會(huì)耗費(fèi)更多的 CPU 時(shí)間以及帶寬,導(dǎo)致 Redis 性能下降。由于 Redis 還是單線程的,處理 大key 的操作進(jìn)而會(huì)阻塞其他請(qǐng)求的處理,從而影響系統(tǒng)性能。
- 持久化效率降低:在進(jìn)行持久化操作時(shí),AOF與RDB都會(huì)因?yàn)樵?nbsp;大key 耗費(fèi)更多的時(shí)間,從而延遲持久化時(shí)間,分布式環(huán)境下甚至?xí)斐删彺娌灰恢隆?/li>
- 網(wǎng)絡(luò)傳輸延遲:大key 在進(jìn)行網(wǎng)絡(luò)傳輸時(shí)會(huì)增加網(wǎng)絡(luò)傳輸?shù)难舆t,在分布式環(huán)境下進(jìn)行數(shù)據(jù)同步時(shí)可能會(huì)造成數(shù)據(jù)的不一致。
2.熱 key 的影響
- CPU占用率高:因?yàn)槭?nbsp;熱key,所以 CPU 一直占用,進(jìn)而導(dǎo)致Redis實(shí)例的CPU負(fù)載增加。
- 請(qǐng)求阻塞:如果 key 有訪問(wèn)優(yōu)先級(jí),熱key 的存在可能導(dǎo)致請(qǐng)求隊(duì)列中其他的請(qǐng)求被阻塞。
- 響應(yīng)時(shí)間延長(zhǎng):因?yàn)?nbsp;熱key ,其他的請(qǐng)求被阻塞了造成響應(yīng)時(shí)間延長(zhǎng)。
- 性能不均衡:流量訪問(wèn)造成突刺,系統(tǒng)性能的不均衡。
3.小結(jié)
大key 與 熱key 都會(huì)給 Redis 實(shí)例造成一系列的影響,如內(nèi)存占用過(guò)高,CPU 負(fù)載增加,持久化時(shí)間變長(zhǎng),性能下降等。
三、原因分析
1.大 key 產(chǎn)生的原因
產(chǎn)生 大key 的原因有很多種,下面咱就一起看一下工作中經(jīng)常遇到的這幾種。
(1) 存儲(chǔ)大量數(shù)據(jù)
存儲(chǔ)了大量數(shù)據(jù)也是我們經(jīng)常遇到 大key 的最多的原因了。
比如 String 類(lèi)型直接保存了一個(gè)大的文本或者二進(jìn)制數(shù)據(jù);Hash 結(jié)構(gòu)中存儲(chǔ)大量的鍵值對(duì)。
- String
SET zuiyu_large_text_key "very large text content..."
- Hash
HMSET zuiyu_large_hash_key field1 value1 field2 value2 ... fieldN valueN
(2) 緩存時(shí)間設(shè)置不合理
緩存時(shí)間設(shè)置不合理這個(gè)造成 大key 的原因大概是個(gè)隱藏挺深的老 bug,有的業(yè)務(wù)場(chǎng)景,使用 Redis 緩存數(shù)據(jù),業(yè)務(wù)是定時(shí)往該 key 上寫(xiě)數(shù)據(jù),由于該 key 是沒(méi)有設(shè)置緩存時(shí)間的造成這個(gè) key 隨著時(shí)間的流逝,占用的內(nèi)存越來(lái)越多,對(duì)于該點(diǎn),只需要設(shè)置一個(gè)合理的過(guò)期時(shí)間即可。
前提是多次寫(xiě)入不是覆蓋,而是追加才會(huì)有該問(wèn)題。
SETEX zuiyu_key_with_expiry value 3600 # 設(shè)置過(guò)期時(shí)間為3600秒
(3) 數(shù)據(jù)結(jié)構(gòu)使用不當(dāng)
在使用 List 數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)數(shù)據(jù)時(shí),重復(fù)的添加數(shù)據(jù),造成該 key 越來(lái)越大,實(shí)際上業(yè)務(wù)是不需要有重復(fù)的數(shù)據(jù)存在的。
List
LPUSH zuiyu_large_list_key value
(4) 小結(jié)
大key 的產(chǎn)生根本原因就是在一個(gè) key 下面存儲(chǔ)的數(shù)據(jù)多了。
2.熱 key 產(chǎn)生的原因
(1) 熱門(mén)數(shù)據(jù)
熱key 的產(chǎn)生一般意味著系統(tǒng)訪問(wèn)火爆了,但是火爆的只是其中一個(gè)點(diǎn)或者n個(gè)點(diǎn)。類(lèi)似微博中某個(gè)明星的瓜,當(dāng)上頭條的時(shí)候,大量的人去訪問(wèn),造成了該明星所對(duì)應(yīng)的 key 成為 熱key。
(2) 頻繁的更新
某些業(yè)務(wù)場(chǎng)景,單位時(shí)間內(nèi)一直頻繁的對(duì) key 進(jìn)行更新,該 key 也會(huì)成為 熱key。
(3) 熱門(mén)搜索
類(lèi)似于第一中的熱門(mén)數(shù)據(jù),產(chǎn)生了熱門(mén)數(shù)據(jù),該數(shù)據(jù)對(duì)應(yīng)的熱門(mén)關(guān)鍵詞也被大量的用戶去搜索,造成該關(guān)鍵詞被頻繁訪問(wèn),最終導(dǎo)致該 key 也稱為 熱key。
(4) 小結(jié)
熱key 的產(chǎn)生無(wú)外乎熱門(mén)數(shù)據(jù),熱門(mén)數(shù)據(jù)產(chǎn)生的熱門(mén)關(guān)鍵詞以及對(duì)同一個(gè) key 在某段時(shí)間內(nèi)的頻繁訪問(wèn)。
四、解決方案
1.大key的解決方案
- 合理的數(shù)據(jù)結(jié)構(gòu)
- 合理的緩存時(shí)間
- 大key 進(jìn)行拆分為多個(gè) 小key
- 定期對(duì) 大key 進(jìn)行清理
2.熱key的解決方案
- 合理的緩存淘汰策略
- 熱點(diǎn)數(shù)據(jù)分片:將熱點(diǎn)數(shù)據(jù)分散到不同的Redis實(shí)例,提升系統(tǒng)的吞吐量。
- 緩存預(yù)熱:在系統(tǒng)啟動(dòng)或者活動(dòng)高峰開(kāi)啟之前進(jìn)行緩存預(yù)熱,提前將需要的數(shù)據(jù)加載到緩存,減少熱點(diǎn)數(shù)據(jù)首次訪問(wèn)的時(shí)間。
- 隨機(jī)緩存失效時(shí)間:避免大量的key同一時(shí)間批量失效,造成緩存雪崩與緩存穿透。
- 緩存穿透:使用布隆過(guò)濾器進(jìn)行緩存請(qǐng)求過(guò)濾,防止無(wú)效請(qǐng)求進(jìn)入到緩存層。
五、總結(jié)
針對(duì) 大key 我們要盡可能的避免同一個(gè) key 下大量的數(shù)據(jù)。針對(duì) 熱key 我們要合理設(shè)置過(guò)期時(shí)間,增加布隆過(guò)濾器等技術(shù)實(shí)現(xiàn)無(wú)效請(qǐng)求過(guò)濾,對(duì)即將到來(lái)的數(shù)據(jù)進(jìn)行緩存預(yù)熱、熱點(diǎn)數(shù)據(jù)分片處理。