1. 为什么高并发系统必须监控Redis的QPS和TPS?
在电商大促或秒杀活动的技术复盘会上,我经常听到这样的对话:"当时Redis明明没报错,为什么下单会卡住?"、"缓存命中率看着正常,但接口超时了"。这些问题的根源往往在于——我们只监控了Redis的基础健康指标,却忽略了最关键的QPS(Queries Per Second)和TPS(Transactions Per Second)数据。
去年双十一,我们某个核心服务就踩过这个坑。当时Dashboard显示Redis CPU和内存使用率都在安全线内,但实际用户已经遭遇了明显的操作延迟。后来排查发现,某个异常热点Key导致了单分片QPS突破3万,触发了Redis的单线程处理瓶颈。这个案例让我深刻认识到:在高并发系统中,Redis的QPS/TPS监控不是"锦上添花",而是"生死攸关"的生命线指标。
2. Prometheus+Redis Exporter监控方案设计
2.1 组件选型背后的技术权衡
面对市面上众多的监控方案(如Zabbix、Datadog等),我们选择Prometheus的核心原因有三点:
- 多维度数据模型:Prometheus的Metric格式天生支持标签维度,比如可以区分
command=set和command=get的QPS,这对分析命令级性能瓶颈至关重要 - 高效的时序处理:基于TSDB的存储引擎,对高频率采集的QPS指标(通常需要1s粒度)有着天然优势
- 生态完整性:Redis Exporter+Grafana的组合已经形成事实标准,社区有大量现成的Dashboard模板
注意:生产环境建议将Prometheus部署为集群模式。我们曾因单实例Prometheus宕机导致监控黑洞,后来改用VictoriaMetrics作为长期存储后端,稳定性显著提升。
2.2 Redis Exporter的埋点原理
Redis Exporter通过执行INFO命令获取全量指标,其工作流程如下:
bash复制# 典型的信息采集周期(通过--redis.info-refresh-interval参数控制)
每15秒执行一次:redis-cli INFO ALL
↓
解析出160+个指标项(含QPS/TPS相关)
↓
转换为Prometheus格式的metrics
↓
暴露HTTP端点(默认端口9121)
关键指标说明:
redis_commands_total:按命令分类的QPS计数器redis_instantaneous_ops_per_sec:Redis内置估算的瞬时QPSredis_total_net_input_bytes:输入流量(结合时间窗口可计算TPS)
3. 生产级部署实操指南
3.1 安装配置全流程
以Docker Compose部署为例,这是经过线上验证的配置:
yaml复制version: '3'
services:
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
command: ["--maxmemory-policy volatile-lru", "--save 900 1"]
redis_exporter:
image: oliver006/redis_exporter:v1.45.0
ports:
- "9121:9121"
environment:
- REDIS_ADDR=redis://redis:6379
depends_on:
- redis
prometheus:
image: prom/prometheus:v2.40.1
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
对应的Prometheus配置(重点抓取规则):
yaml复制scrape_configs:
- job_name: 'redis'
static_configs:
- targets: ['redis_exporter:9121']
metrics_path: /scrape
relabel_configs:
- source_labels: [__address__]
target_label: instance
replacement: 'redis-production-01'
3.2 关键指标的采集策略优化
默认配置可能无法满足高并发场景需求,需要调整这些参数:
-
采集频率:对于QPS这类波动剧烈的指标,建议将
scrape_interval设为5s(需平衡存储压力)yaml复制global: scrape_interval: 5s evaluation_interval: 15s -
指标过滤:只采集关键指标减少负载(示例保留规则)
yaml复制metric_relabel_configs: - source_labels: [__name__] regex: '(redis_commands_total|redis_instantaneous_ops_per_sec|redis_latency_microseconds)' action: keep -
Exporter调优:增加内存缓存防止OOM
bash复制
docker run -e REDIS_EXPORTER_WEB_TELEMETRY_PATH=/metrics \ -e REDIS_EXPORTER_LOG_FORMAT=json \ -e REDIS_EXPORTER_REDIS_METRICS_INTERVAL=10s \ oliver006/redis_exporter
4. Grafana看板设计与异常诊断
4.1 必须监控的黄金指标
根据Google SRE理论,我们设计了一套四维监控体系:
| 指标类型 | PromQL示例 | 告警阈值建议 |
|---|---|---|
| 吞吐量(QPS) | rate(redis_commands_total[1m]) | 单分片>1.5万(视机型调整) |
| 延迟 | histogram_quantile(0.99, sum(redis_latency_microseconds_bucket) by (le)) | >50ms |
| 错误率 | rate(redis_rejected_connections_total[1m]) | >0 |
| 饱和度 | redis_memory_used_bytes / redis_memory_max_bytes | >80% |
4.2 动态基线告警策略
静态阈值在高并发场景下容易误报,我们采用时序预测告警:
sql复制# 基于7天同期数据计算动态基线
(
predict_linear(redis_instantaneous_ops_per_sec[1d], 3600)
>
avg_over_time(redis_instantaneous_ops_per_sec[7d] offset 1w) * 1.5
)
4.3 典型问题排查案例
场景:某次大促期间QPS突增导致Redis响应变慢
排查路径:
- 发现
redis_cpu_system_seconds_total增速异常 - 按命令分解QPS:
topk(3, rate(redis_commands_total[5m])) - 定位到
HGETALL命令占比超60% - 检查对应Key发现是10MB的大Hash
- 解决方案:拆分为多个小Hash + 本地缓存热点数据
5. 性能调优进阶技巧
5.1 读写分离架构下的监控要点
当使用Redis Replica做读扩展时,需要特别关注:
- 主从延迟监控:
bash复制redis_replica_lag_seconds{role="slave"} > 10 - 从库QPS均衡性检查:
sql复制stddev( rate(redis_commands_total{role="slave"}[5m]) ) > 1000
5.2 大Key检测的Prometheus实现
通过组合指标发现潜在大Key:
sql复制# 找出内存增长最快的Key
sort_desc(
delta(redis_memory_usage_bytes{key!=""}[1h])
)
# 找出访问最频繁的Key
topk(10, rate(redis_key_access_count[1h]))
5.3 客户端连接池监控
很多性能问题其实出在客户端,建议监控:
- 连接数波动:
redis_clients_connected - 连接等待时间:
redis_client_longest_output_list - 输入缓冲区溢出:
increase(redis_clients_rejected_total[1h])
我们在Java应用中添加的监控埋点示例:
java复制// 使用Micrometer暴露连接池指标
registry.gauge("redis.pool.active", pool, p -> p.getNumActive());
registry.gauge("redis.pool.idle", pool, p -> p.getNumIdle());
6. 生产环境踩坑实录
-
Exporter内存泄漏:早期版本在Redis实例数超过50时会出现OOM,解决方案:
bash复制# 限制Exporter内存用量 docker run --memory=512m redis_exporter -
Prometheus抓取超时:当Redis响应慢时会导致抓取失败,需要调整:
yaml复制scrape_configs: - job_name: 'redis' scrape_timeout: 30s -
指标基数爆炸:某次误将客户端IP作为标签导致指标激增,修复方案:
yaml复制metric_relabel_configs: - action: labeldrop regex: client_ip -
集群模式监控盲区:Redis Cluster需要为每个节点单独部署Exporter,我们开发了自动发现脚本:
python复制# 通过CLUSTER NODES命令动态发现节点 nodes = redis.execute_command('CLUSTER NODES').split('\n') for node in nodes: ip, port = parse_node_info(node) start_exporter_process(ip, port)
