【数据库】【Redis】缓存监控体系深度解析:从 BigKeys 到慢查询

Redis 缓存监控体系深度解析:从 BigKeys 到慢查询

Redis 作为高性能缓存,在生产环境中必须建立完善的监控体系。本文将深入剖析 BigKeys、HotKeys、慢查询 三大核心监控维度,并提供生产级诊断与优化方案。


一、BigKeys(大Key)监控与治理

1.1 什么是大Key?

大Key定义:单个 Key 的内存占用过大,通常指:

  • String 类型:value > 10KB(或 > 1MB)
  • Hash/List/Set/Zset:元素数量 > 5000 个(或总大小 > 10MB)

大Key危害

  • 阻塞单线程 :Redis 单线程模型,操作大Key会阻塞其他请求,导致延迟飙升(从微秒级到秒级)
  • 内存溢出:集群架构下,大Key导致某个子节点内存率先耗尽,引发 OOM
  • 网络拥塞:大Key的传输占用大量带宽,影响其他请求
  • 删除卡顿:DEL 大Key会阻塞数秒甚至数十秒

1.2 大Key识别方法

**方法1:redis-cli --bigkeys(官方推荐)
bash 复制代码
# 遍历所有Key,分析每种类型的最大Key
redis-cli -h <host> -p <port> -a <password> --bigkeys

# 扫描间隔 0.1 秒(避免影响业务)
redis-cli --bigkeys -i 0.1

# 输出示例:
# Sampled 1000000 keys in the hash slot 0...
# Sampled 1000000 keys in the hash slot 1...
# Biggest string found 'user:profile:1000' has 10485760 bytes
# Biggest hash found 'order:items:2024' has 125000 fields

优点:无需安装插件,官方原生支持

缺点 :对性能有影响,禁止在业务高峰期使用

方法2:离线 RDB 文件分析(零影响)
bash 复制代码
# 下载 RDB 文件到本地分析
redis-cli --rdb dump.rdb

# 使用 rdb-tools 分析
rdb --command memory dump.rdb > memory.csv

# 分析结果排序
sort -t, -k4nr memory.csv | head -20

阿里云/华为云控制台 :提供离线全量 Key 分析功能,对线上服务无影响

方法3:MEMORY USAGE 精确查询
bash 复制代码
# 查询单个 Key 的内存占用(精确)
MEMORY USAGE "user:profile:1000"
# 返回:10485760 (bytes)

# 配合 SCAN 批量扫描
redis-cli --scan --pattern "user:*" | xargs -L 1 redis-cli MEMORY USAGE

1.3 大Key解决方案

方案1:数据拆分(核心策略)

大 Hash 拆分

java 复制代码
// 原大Key:user:profile:{userId} 包含100万字段
// 拆分后:user:profile:{userId}:{hash(userId)%100}
int shard = userId % 100;
String key = "user:profile:" + userId + ":" + shard;

// 读取时聚合
List<String> results = jedisCluster.hmget(
    "user:profile:" + userId + ":*",
    "field1", "field2"
);

大 String 拆分

java 复制代码
// 将 10MB JSON 拆分为多个 Key
String baseKey = "article:content:" + articleId + ":";
jedisCluster.set(baseKey + "part1", json.substring(0, 1024*1024));
jedisCluster.set(baseKey + "part2", json.substring(1024*1024, 2048*1024));
// 读取时拼接
方案2:数据压缩
java 复制代码
// 使用 LZ4/Snappy 压缩
byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor()
    .compress(originalJson.getBytes());

// 存储为二进制
jedisCluster.set(key.getBytes(), compressed);
方案3:异步删除(UNLINK)
bash 复制代码
# DEL 会阻塞,UNLINK 会后台删除
UNLINK "user:profile:1000"

1.4 大Key监控与告警

定时任务扫描

java 复制代码
@Scheduled(cron = "0 0 3 * * ?") // 每日凌晨低峰期
public void scanBigKeys() {
    Set<String> keys = jedisCluster.keys("user:*");
    for (String key : keys) {
        Long size = jedisCluster.memoryUsage(key);
        if (size > 10 * 1024 * 1024) { // > 10MB
            alarmService.send("大Key告警: " + key + " 大小: " + size + "bytes");
        }
    }
}

阿里云/华为云:控制台配置大Key自动告警阈值


二、HotKeys(热Key)监控与治理

2.1 什么是热Key?

热Key定义:访问频率极高的 Key,通常 QPS > 5000

热Key危害

  • CPU 打满:单个 Key 的请求由单核处理,成为性能瓶颈
  • 单点瓶颈:集群架构下,某个分片节点压力过大
  • 缓存击穿:热Key过期瞬间,请求洪峰打爆数据库

典型案例

  • 秒杀活动商品详情页
  • 热门视频弹幕
  • 首页 Banner 配置

2.2 热Key识别方法

方法1:redis-cli --hotkeys(推荐)
bash 复制代码
# Redis 4.0+ 原生支持
redis-cli -h <host> -p <port> -a <password> --hotkeys

# 输出示例:
# Summary: 
# Key 1: "product:detail:9527"  QPS: 15234
# Key 2: "user:session:10086"  QPS: 8921

# **注意**:对性能有影响,**禁止高峰期使用**
方法2:MONITOR 命令(慎用)
bash 复制代码
# 实时监控所有命令(性能杀手,降低50%性能)
redis-cli MONITOR | grep "GET\|SET"

# 统计 key 访问频率
redis-cli MONITOR | awk '{print $2}' | sort | uniq -c | sort -nr | head -20

# **严重警告**:只能在非高峰期短时间使用
方法3:业务层埋点(最准确)
java 复制代码
// 在访问 Redis 处埋点
public String get(String key) {
    long start = System.nanoTime();
    String value = jedisCluster.get(key);
    long qps = metrics.recordQuery(key, start); // 记录 QPS
    
    if (qps > 5000) {
        hotkeyService.report(key, qps); // 上报热Key
    }
    return value;
}

阿里云/华为云 :控制台提供实时热Key分析,对业务无影响


2.3 热Key解决方案

方案1:本地缓存(L1)最常用
java 复制代码
// Caffeine 本地缓存(有效期 1-2 分钟)
private final Cache<String, String> localCache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(Duration.ofMinutes(2))
    .build();

public String getProductDetail(Long productId) {
    String key = "product:detail:" + productId;
    
    // 1. 本地缓存
    String json = localCache.getIfPresent(key);
    if (json != null) return json;
    
    // 2. Redis 集群
    json = jedisCluster.get(key);
    if (json != null) {
        localCache.put(key, json); // 回填本地缓存
        return json;
    }
    
    // 3. 数据库
    Product product = productMapper.selectById(productId);
    json = JSON.toJSONString(product);
    localCache.put(key, json);
    jedisCluster.setex(key, 300, json);
    return json;
}
方案2:读写分离(主从架构)
yaml 复制代码
# redis.conf
# 从节点配置为只读
slave-read-only yes
java 复制代码
// 读从节点
Jedis slaveJedis = new Jedis("slave-ip", 6379);
String value = slaveJedis.get("hotkey");

// 写主节点
jedisCluster.set("hotkey", newValue); // 自动同步到从
方案3:热Key复制 + 随机访问
java 复制代码
// 将 hotkey 复制为多个副本
int replicaCount = 10;
for (int i = 0; i < replicaCount; i++) {
    String replicaKey = "hotkey:" + i;
    jedisCluster.set(replicaKey, value);
}

// 读取时随机路由
int randomIndex = ThreadLocalRandom.current().nextInt(replicaCount);
String replicaKey = "hotkey:" + randomIndex;
String value = jedisCluster.get(replicaKey);

2.4 热Key监控与告警

实时告警

java 复制代码
// 基于埋点的实时告警
@Scheduled(fixedRate = 1000) // 每秒检查
public void checkHotkeys() {
    Map<String, Long> stats = metrics.getQpsStats();
    stats.forEach((key, qps) -> {
        if (qps > 5000) {
            alarmService.send("热Key告警: " + key + " QPS: " + qps);
            // 自动触发本地缓存
            enableLocalCacheForKey(key);
        }
    });
}

三、慢查询分析与优化

3.1 慢查询日志

配置

bash 复制代码
# redis.conf
slowlog-log-slower-than 10000  # 超过 10ms 记录(微秒)
slowlog-max-len 1000           # 保留最近 1000 条

查看慢查询

bash 复制代码
# 查看最近 10 条慢查询
redis-cli SLOWLOG GET 10

# 输出格式:
# 1) (integer) 123  # 唯一ID
# 2) (integer) 1676888923  # 时间戳
# 3) (integer) 15000  # 执行时长(微秒)= 15ms
# 4) 1) "HGETALL"     # 命令
#    2) "user:profile:1000"  # Key
# 5) "192.168.1.10:54321"  # 客户端地址

清空慢查询日志

bash 复制代码
SLOWLOG RESET

3.2 慢查询根因分析

根因1:高复杂度命令 O(N)

典型慢命令

命令 时间复杂度 场景
KEYS pattern O(N) 遍历所有 Key
HGETALL O(N) 读取大 Hash
SMEMBERS O(N) 读取大 Set
SORT O(N+M*log(M)) 排序
SINTER O(N*M) 集合交集

优化方案

bash 复制代码
# KEYS * → SCAN 0 渐进式遍历
SCAN 0 MATCH "user:*" COUNT 1000

# HGETALL → HSCAN 分批读取
HSCAN "user:profile:1000" 0 COUNT 100

# SMEMBERS → SSCAN
SSCAN "hot:set" 0 COUNT 100
根因2:大Key操作
bash 复制代码
# 删除 10MB 的 Key(阻塞 50ms)
DEL "bigkey:content"

# 优化:异步删除
UNLINK "bigkey:content"  # 非阻塞,后台线程删除
根因3:热Key集中访问
bash 复制代码
# 单个 Key 的 QPS > 10000,CPU 单核打满
# 解决方案见 "热Key治理" 章节

3.3 慢查询监控与告警

定时分析

java 复制代码
@Scheduled(cron = "0 */5 * * * ?") // 每 5 分钟
public void analyzeSlowLog() {
    List<SlowLog> logs = jedisCluster.slowlogGet(100);
    
    logs.stream()
        .filter(log -> log.getExecutionTime() > 50000) // > 50ms
        .forEach(log -> {
            alarmService.send("慢查询告警: " + log.getCommand() + " " + 
                            log.getKey() + " 耗时: " + log.getExecutionTime() + "μs");
        });
}

慢查询可视化

  • 阿里云/华为云:控制台自动展示慢查询 Top10
  • 自建监控 :通过 SLOWLOG GET 采集到 Prometheus + Grafana

四、综合监控体系:从指标到告警

4.1 监控指标体系

指标类别 核心指标 阈值 监控工具
性能 QPS、延迟 P99 < 10ms INFO stats
内存 内存占用、碎片率 used_memory_human < 80% INFO memory
大Key Key 大小 > 10MB 告警 --bigkeys
热Key Key 访问频率 QPS > 5000 告警 --hotkeys
慢查询 执行时长 > 10ms 告警 SLOWLOG GET
命中率 keyspace_hits / (hits + misses) > 90% INFO keyspace

4.2 生产级告警配置

Prometheus + Grafana 监控大盘

yaml 复制代码
# Prometheus 采集配置
- job_name: 'redis'
  static_configs:
    - targets: ['redis:9121']
  scrape_interval: 15s

# 告警规则
- alert: RedisHighMemoryUsage
  expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.8
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "Redis 内存使用率超过 80%"

Redis Exporter 指标

bash 复制代码
# 安装 redis_exporter
docker run -d --name redis_exporter \
  -p 9121:9121 \
  oliver006/redis_exporter \
  --redis.addr=redis://192.168.1.20:6379

4.3 自动化治理闭环

监控采集
告警触发
根因分析
大Key?
热Key?
慢查询?
自动拆分/压缩
启用本地缓存
SQL优化/SCAN替代
效果验证
监控收敛

京东故障排查模板

  1. 快速诊断slowlog--hotkeys--bigkeys
  2. 根因定位:O(N)命令、大Key、热Key
  3. 紧急止血:UNLINK、本地缓存、读写分离
  4. 长期优化:代码改造、监控闭环

五、云厂商工具对比

工具 大Key分析 热Key分析 慢查询 优点 价格
阿里云 Redis ✅ 离线分析 ✅ 实时监控 ✅ 自动告警 对业务无影响 免费
华为云 DCS ✅ 离线分析 ✅ 实时监控 ✅ 自动告警 集成监控平台 免费
redis-cli ✅ --bigkeys ✅ --hotkeys ✅ SLOWLOG 原生支持 开源免费
redis_exporter ✅ 采集 Prometheus集成 开源免费

六、生产环境最佳实践

6.1 监控 checklist

  • 每日扫描 :凌晨低峰期运行 --bigkeys
  • 热Key监控:接入云厂商工具或业务埋点
  • 慢Query告警:配置 > 10ms 的告警规则
  • 内存水位:设定 80% 告警阈值
  • 命中率:目标 > 90%,低于 80% 立即排查

6.2 优化口诀

复制代码
大Key三方案:拆分、压缩、UNLINK
热Key三方案:本地缓存、读写分离、分片
慢查询三方案:SCAN、HSCAN、SSCAN
监控三要素:QPS、内存、命中率

总结

监控项 识别工具 危害 解决方案 优先级
BigKeys --bigkeys、RDB分析 阻塞单线程、OOM 拆分、压缩、UNLINK 🔴 高
HotKeys --hotkeys、业务埋点 CPU打满、单点瓶颈 本地缓存、读写分离 🔴 高
慢查询 SLOWLOG GET 阻塞其他请求 SCAN替代KEYS、分批读取 🟡 中

Redis 监控的本质是 "防范于未然" 。通过自动化工具识别风险,通过分级告警快速响应,通过闭环治理持续优化,才能保障缓存系统的高可用与高性能。

相关推荐
小马爱打代码2 小时前
实时搜索:SpringCloud + Elasticsearch + Redis + Kafka
redis·elasticsearch·spring cloud
张乔242 小时前
spring boot项目中设置默认的方法实现
java·数据库·spring boot
TDengine (老段)2 小时前
TDengine R 语言连接器入门指南
大数据·数据库·物联网·r语言·时序数据库·tdengine·涛思数据
heartbeat..2 小时前
数据库性能优化:SQL 语句的优化(原理+解析+面试)
java·数据库·sql·性能优化
yuhaiqun19892 小时前
SQL+VSCode实战指南:AI赋能高效数据库操作
数据库·人工智能·经验分享·vscode·sql·学习·学习方法
韩立学长2 小时前
基于Springboot琴行学生课程信息管理系统2gt392wb(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
逐浪CMS发哥2 小时前
windows删除字体缓存(即删除用户目录下的字体文件)
windows·缓存
Mr.H01272 小时前
Linux常见压缩命令
linux·服务器·数据库
咕噜企业分发小米2 小时前
阿里云与华为云基因测序数据同步的日志内容中,哪些字段对于故障排查最为关键?
数据库·阿里云·华为云