Redis 缓存应用与热点

Redis 缓存应用与热点问题实战


1.1 缓存读写流程:Cache Aside(旁路缓存模式)

📌 工作流程:

  1. 先从缓存查询数据;
  2. 如果没有命中(cache miss),从数据库加载;
  3. 将数据写入缓存;
  4. 返回数据给业务;
  5. 更新数据时,先更新数据库,再删除缓存。

✅ Python 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import redis
import time
from functools import wraps

r = redis.Redis(host='localhost', port=6379, db=0)

def cache_aside(key_prefix, ttl=300):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
cache_key = f"{key_prefix}:{args[0]}"
result = r.get(cache_key)
if result:
return result.decode('utf-8')
result = func(*args, **kwargs)
if result:
r.setex(cache_key, ttl, result)
return result
return wrapper
return decorator

# 模拟数据库访问
@cache_aside("user_info", ttl=60)
def get_user_from_db(user_id):
print("访问数据库...")
time.sleep(1)
return f"user_{user_id}_data"

1.2 热键(Hot Key)实战分析

🔥 什么是热键?

热键是指访问频率极高的某个 key,常见于以下场景:

  • 爆款商品详情页
  • 明星账号信息
  • 热点新闻推送
  • 用户个性化首页

🔍 热键检测方法

方法一:使用 MONITOR(开发环境使用)

1
redis-cli MONITOR

输出将展示所有命令,例如:

1
2
3
"GET" "product:123"
"GET" "product:123"
"GET" "product:123"

可以观察是否有单一 key 高频出现。

方法二:使用 slowlog 检测慢查询

1
127.0.0.1:6379> SLOWLOG GET

配合监控记录命中频率较高的 key。

方法三:接入 APM 工具(企业推荐)

  • SkyWalking
  • Pinpoint
  • ELK(日志聚合)+ Kibana 分析热点 key 访问日志

🛠️ 企业解决方案

问题 解决方式
Redis 单点过载 本地缓存 + Redis 两级结构(如 Guava + Redis)
热点 key TTL 同步过期 TTL 随机化,避免雪崩
热点数据库穿透 添加互斥锁,打散请求,加载中给默认值
并发缓存穿透 异步刷新缓存,使用布隆过滤器防穿透

✅ Python 示例:异步缓存刷新 + TTL 打散

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import redis
import random
import time
from threading import Thread

r = redis.Redis()

def get_data_with_hotkey(key):
value = r.get(key)
if value:
return value.decode('utf-8')

# 加互斥锁防止击穿(简化)
if not r.setnx(f"{key}:lock", 1):
time.sleep(0.1) # 打散请求
return get_data_with_hotkey(key)

# 模拟数据库
value = f"data_from_db_{key}"
ttl = 60 + random.randint(0, 30) # TTL 随机打散
r.setex(key, ttl, value)
r.delete(f"{key}:lock")
return value

1.3 大键(Big Key)问题分析

🧱 什么是大键?

单个 Redis key 对应的数据量非常大:

  • 超长字符串(大 HTML 页面)
  • 数万个成员的 Set、ZSet、Hash
  • 单 key 占用内存超过 1MB 甚至更多

📈 排查大键的方法

方法一:MEMORY USAGE key

1
127.0.0.1:6379> MEMORY USAGE large_key

返回该 key 占用的字节数。

方法二:结合 RANDOMKEY、DUMP 和 RESTORE 检测

1
2
127.0.0.1:6379> RANDOMKEY
127.0.0.1:6379> DUMP large_key

对不确定的 key 进行抽样分析。

方法三:使用脚本或监控工具定期巡检


💡 大键问题的影响

问题 描述
阻塞主线程 Redis 是单线程,大键操作时间长会阻塞
哨兵主从切换失败 大 key 同步时间过长导致主从失效
集群抖动 某节点频繁操作大 key 导致响应缓慢

🧩 企业级处理建议

场景 建议
HTML 页面的缓存 切片或分页存储为多个 key
Hash 超大 使用嵌套结构存储多个小 Hash,控制字段数 < 5000
Set/ZSet 分片管理,支持分页读取
所有大 key 设置合理的 TTL 防止缓存污染

✅ Python 示例:自动检测大键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import redis

r = redis.Redis()

def scan_big_keys(threshold=1024 * 100): # 100KB
cursor = 0
big_keys = []
while True:
cursor, keys = r.scan(cursor, count=100)
for key in keys:
usage = r.memory_usage(key)
if usage and usage > threshold:
big_keys.append((key.decode(), usage))
if cursor == 0:
break
return big_keys

if __name__ == "__main__":
results = scan_big_keys()
for k, v in results:
print(f"大键: {k}, 大小: {v / 1024:.2f} KB")

✅ 总结:缓存优化 Checklist

  • 使用 Cache Aside 实现高可用缓存逻辑
  • 检测并打散热键,防止 Redis 被打爆
  • 避免大键:分页、小集合分拆、合理 TTL
  • 使用监控工具定时发现大键/热键
  • 利用 APM + 日志系统定位缓存异常点

Redis 缓存应用与热点
https://dreamshao.github.io/2025/07/17/redis缓存应用与热点/
作者
Yun Shao
发布于
2025年7月17日
许可协议