Redis 熱 Key 問題的解決
在高并發(fā)的分布式系統(tǒng)中,Redis 作為高性能的內(nèi)存數(shù)據(jù)庫,廣泛用于緩存、會(huì)話存儲(chǔ)、計(jì)數(shù)器等場景。然而,隨著業(yè)務(wù)規(guī)模的增長,熱 Key(Hot Key)問題逐漸成為影響系統(tǒng)穩(wěn)定性和性能的重要隱患。
什么是熱 Key?
熱 Key 是指在 Redis 中被高頻訪問的某個(gè) Key,其訪問頻率遠(yuǎn)超其他 Key,導(dǎo)致該 Key 所在的 Redis 實(shí)例或節(jié)點(diǎn)成為系統(tǒng)瓶頸。
典型特征:
- 單個(gè) Key 的 QPS(每秒查詢數(shù))極高,可能達(dá)到數(shù)萬甚至更高。
- 該 Key 集中在一個(gè) Redis 節(jié)點(diǎn)上,導(dǎo)致該節(jié)點(diǎn) CPU、內(nèi)存、網(wǎng)絡(luò)帶寬負(fù)載過高。
- 其他 Key 的訪問正常,但該 Key 的訪問延遲明顯升高,甚至引發(fā)超時(shí)或服務(wù)不可用。
熱 Key 的常見場景
- 秒殺/搶購商品信息
- 某個(gè)熱門商品詳情被大量用戶頻繁查詢。
- 熱點(diǎn)新聞或文章
- 突發(fā)新聞的閱讀量、點(diǎn)贊數(shù)等 Key 被高頻訪問。
- 全局配置或公共數(shù)據(jù)
- 如系統(tǒng)開關(guān)、活動(dòng)配置等,所有服務(wù)都依賴同一個(gè) Key。
- 大 V 用戶數(shù)據(jù)
- 某個(gè)明星用戶的粉絲列表、動(dòng)態(tài)被大量訪問。
- 緩存穿透/擊穿后的集中重建
- 大量請求同時(shí)重建同一個(gè)緩存 Key。
熱 Key 的危害
| 問題 | 影響 |
|---|---|
| 單點(diǎn)瓶頸 | 熱 Key 集中在一個(gè) Redis 節(jié)點(diǎn),導(dǎo)致該節(jié)點(diǎn)負(fù)載過高,影響其他 Key 的訪問。 |
| 網(wǎng)絡(luò)帶寬耗盡 | 高頻讀寫導(dǎo)致網(wǎng)絡(luò) IO 達(dá)到瓶頸,響應(yīng)變慢。 |
| CPU 過載 | Redis 單線程處理命令,熱 Key 導(dǎo)致主線程阻塞,影響其他請求。 |
| 緩存雪崩風(fēng)險(xiǎn) | 若熱 Key 失效,大量請求直接打到數(shù)據(jù)庫,可能壓垮 DB。 |
| 主從延遲 | 寫熱 Key 時(shí),主節(jié)點(diǎn)壓力大,同步到從節(jié)點(diǎn)延遲增加。 |
如何發(fā)現(xiàn)熱 Key?
方法一:使用redis-cli --hotkeys(Redis 自帶工具)
這是最簡單直接的方式,適用于 Redis 4.0+ 版本。
原理
Redis 內(nèi)置了基于 LFU(Least Frequently Used)算法 的熱點(diǎn) Key 發(fā)現(xiàn)機(jī)制。通過采樣命令訪問頻率,自動(dòng)識別出訪問最頻繁的 Key。
使用方式
# 連接 Redis 并啟動(dòng)熱 Key 檢測 redis-cli --hotkeys # 可指定 host 和 port redis-cli -h 127.0.0.1 -p 6379 --hotkeys
輸出示例
# Scanning the entire keyspace to find hot keys as well as
# average sizes per pattern of keys.
# 1 hottest key found at 'user:profile:10086' with 12532 hits
# 2 hottest key found at 'product:detail:hot' with 9823 hits
注意事項(xiàng)
- 需要開啟
maxmemory-policy為 LFU 相關(guān)策略(如allkeys-lfu或volatile-lfu),否則可能無效。 - 僅能發(fā)現(xiàn) 讀操作多的 Key,寫操作不會(huì)計(jì)入 LFU 計(jì)數(shù)。
方法二:SLOWLOG分析慢查詢
雖然不直接找“熱 Key”,但可以間接發(fā)現(xiàn)性能瓶頸。
命令
# 查看最近 10 條慢查詢 SLOWLOG GET 10 # 查看慢查詢總數(shù) SLOWLOG LEN # 重置慢日志 SLOWLOG RESET
輸出字段說明
id: 日志 IDtimestamp: 執(zhí)行時(shí)間戳duration: 執(zhí)行耗時(shí)(微秒)cmd: 完整命令(包含 Key 名)
如果某個(gè) Key 多次出現(xiàn)在慢日志中,很可能是熱 Key 或大 Key。
配置慢查詢閾值
在 redis.conf 中設(shè)置:
slowlog-log-slower-than 10000 # 超過 10ms 的命令記錄 slowlog-max-len 1024 # 最多保存 1024 條日志
熱 Key 的解決方案
方案 1:本地緩存 + Redis(二級緩存)
思路:在應(yīng)用層使用本地緩存(如 Caffeine、Guava Cache)緩存熱 Key,減少對 Redis 的直接訪問。
// 示例:使用 Caffeine 緩存熱 Key
LoadingCache<String, String> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(key -> redis.get(key));
String value = cache.get("hot:product:123");優(yōu)點(diǎn):簡單高效,顯著降低 Redis 壓力。
缺點(diǎn):存在緩存不一致問題,需設(shè)置合理過期時(shí)間。
方案 2:Key 拆分(分片)
思路:將一個(gè)熱 Key 拆分為多個(gè)子 Key,分散訪問壓力。
# 原始熱 Key SET hot:product:123 "details" # 拆分為多個(gè) Key SET hot:product:123:1 "details_part1" SET hot:product:123:2 "details_part2"
讀取時(shí):隨機(jī)選擇一個(gè)子 Key 讀取,或合并多個(gè)。
適用場景:讀多寫少,且數(shù)據(jù)可拆分。
方案 3:讀寫分離 + 從庫擴(kuò)容
思路:將讀請求打到 Redis 從庫,寫請求打到主庫。
- 增加從節(jié)點(diǎn)數(shù)量,分擔(dān)讀壓力。
- 使用 Redis Cluster 或主從架構(gòu),合理分配讀請求。
注意:從庫有延遲,對一致性要求高的場景慎用。
方案 4:使用 Redis 集群(Cluster)
思路:通過 Redis Cluster 將 Key 分布到多個(gè)節(jié)點(diǎn),避免單點(diǎn)過熱。
- Redis Cluster 使用 CRC16(key) % 16384 計(jì)算槽位,自動(dòng)分片。
- 熱 Key 仍可能集中在某個(gè)槽位,但可通過 手動(dòng)遷移槽位 分散。
建議:為特別熱的 Key 單獨(dú)部署一個(gè) Redis 實(shí)例。
方案 5:異步更新 + 預(yù)加載
思路:避免大量請求同時(shí)觸發(fā)緩存重建。
- 使用 定時(shí)任務(wù) 預(yù)先加載熱 Key。
- 緩存失效前,異步刷新,避免集中重建。
// 使用 ScheduledExecutorService 定時(shí)刷新 scheduler.scheduleAtFixedRate(this::refreshHotKey, 0, 4, TimeUnit.MINUTES);
方案 6:限流與降級
思路:在應(yīng)用層對熱 Key 訪問進(jìn)行限流,防止系統(tǒng)崩潰。
- 使用 Sentinel、Hystrix 等熔斷限流框架。
- 當(dāng)訪問超過閾值時(shí),返回默認(rèn)值或降級數(shù)據(jù)。
@SentinelResource(value = "getHotKey", blockHandler = "handleHotKey")
public String getHotKey() {
return redis.get("hot:key");
}
public String handleHotKey(BlockException ex) {
return "default_value";到此這篇關(guān)于Redis 熱 Key 問題的解決的文章就介紹到這了,更多相關(guān)Redis 熱 Key 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis結(jié)合Caffeine兩級緩存的三種實(shí)現(xiàn)方式
本文主要介紹了Redis結(jié)合Caffeine兩級緩存的實(shí)現(xiàn)示例,通過手動(dòng)、Spring注解及自定義切面三種方式實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2025-08-08
Redis和數(shù)據(jù)庫雙寫一致性問題的解決方案
文章探討了Redis與數(shù)據(jù)庫雙寫一致性問題,提出四種解決方案:先更新數(shù)據(jù)庫再刪除緩存(推薦),延時(shí)雙刪避免并發(fā)不一致,監(jiān)聽數(shù)據(jù)庫變更實(shí)現(xiàn)最終一致性,加分布式鎖保障強(qiáng)一致,核心原則是優(yōu)先保證數(shù)據(jù)庫正確性,緩存操作可失敗重試,強(qiáng)一致性需犧牲性能2025-08-08
Redis實(shí)現(xiàn)分布式Session管理的機(jī)制詳解
這篇文章主要介紹了Redis實(shí)現(xiàn)分布式Session管理的機(jī)制詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
Redis高效查詢大數(shù)據(jù)的實(shí)踐與優(yōu)化詳細(xì)指南
Redis 是一種高性能的鍵值存儲(chǔ)數(shù)據(jù)庫,廣泛應(yīng)用于緩存,排行榜,計(jì)數(shù)器等場景,本文將圍繞如何高效查詢Redis中滿足條件的數(shù)據(jù)展開討論,感興趣的小伙伴可以了解下2025-04-04
解析Redis 數(shù)據(jù)結(jié)構(gòu)之簡單動(dòng)態(tài)字符串sds
Redis 的 string 類型為何使用sds而不是 C 字符串,本文主要介紹 string 的數(shù)據(jù)結(jié)構(gòu)—— 簡單動(dòng)態(tài)字符串(Simple Dynamic String) 簡稱sds的相關(guān)知識,需要的朋友可以參考下2021-11-11
Redis實(shí)現(xiàn)延遲任務(wù)的常見方案詳解
延遲任務(wù)(Delayed?Task)是指在未來的某個(gè)時(shí)間點(diǎn),執(zhí)行相應(yīng)的任務(wù),本文為大家整理了Redis實(shí)現(xiàn)延遲任務(wù)的幾個(gè)常見方案,希望對大家有所幫助2024-04-04
redis?設(shè)置生存和過期時(shí)間的原理分析
這篇文章主要介紹了redis?設(shè)置生存和過期時(shí)間的原理,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
Centos7.3安裝Redis4.0.6詳細(xì)圖文教程
這篇文章主要介紹了Centos7.3安裝Redis4.0.6詳細(xì)教程圖解,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10

