多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Redis监控不用INFO,redis_exporter从部署到告警实战

Redis监控不用INFO,redis_exporter从部署到告警实战 1. 为什么监控Redis不能靠INFO命令得专门拉一个exporter干运维或者后端时间长了几乎都会遇到这种场景线上Redis突然响应变慢或者内存飙升你第一反应是登录服务器敲redis-cli INFO看两眼。内存满了连接数涨了还是有大key在作妖信息确实能看到一点但也就仅此而已。redis exporter 这个工具就是专门解决Redis状态看不全、看不及时、没法历史回溯的问题。它把Redis的运行数据转成Prometheus能识别的指标格式再由Prometheus持续抓取最终在Grafana上画成趋势图、配上告警。简单说INFO是一条一条手动查的状态快照redis exporter是一套自动化的、带时间序列的监控数据采集器。这篇手册适合谁正在给Redis做基础监控的运维、想排查线上Redis问题的后端开发、以及搭了K8s或Docker环境需要统一观测Redis状态的平台工程师。我会从部署方式、配置项、核心指标、告警规则到踩坑记录把整套东西讲透。1.1 INFO的四个section够不够用Redis自带的INFO命令其实内容很全Memory、Clients、Persistence、Stats、Replication、Keyspace这些section都有。但问题不在内容全不全而是它的使用方式。靠手动敲命令只能看到当前这一刻的状态Redis是不是五分钟前就内存告急了连接数是什么时候开始涨的缓存穿透是什么时候开始频繁发生的这些问题INFO给不了答案。另一个痛点是多实例场景。一个业务环境里往往有主从、哨兵、集群可能有十几个Redis节点。一台一台登录上去敲INFO运维效率极低而且容易漏。就算写成脚本循环执行数据也只能落在本地文件里缺乏统一的采集、存储、可视化链路。redis exporter的做法是每个Redis节点旁边挂一个采集器你只要配置好它的连接信息它会周期性去执行类似INFO的命令把结果整理成结构化的指标通过HTTP端口暴露出来。Prometheus那边设置一个target到点自动来抓数据数据落在时序数据库里随时可以查历史趋势。这才是监控该有的形态。1.2 exporter的定位把Redis翻译成Prometheus时序数据很多人第一次看到redis exporter会困惑它到底是一个独立的服务还是一个Redis插件答案是前者完全不用改动Redis本身。它就是一个独立的进程通过Redis的TCP协议和Redis服务端通信。你可以把它理解成一个翻译官——Redis吐出来的内部状态数据经过这个翻译官变成Prometheus的metrics格式。这套设计非常巧妙的一点是解耦。Redis那边不需要装任何额外的模块exporter这边也不依赖特定的Redis版本只要Redis的INFO、CONFIG这些命令还能用exporter就能正常工作。我见过从Redis 3.x到7.x的混合环境一个exporter进程配了多个实例参数全部正常采集兼容性很稳。数据链路也不复杂Redis节点 --TCP INFO/CLIENT LIST/SLOWLOG-- redis_exporter进程 --HTTP :9121-- Prometheus --查询-- Grafana整个过程里你只需要关注两件事exporter怎么部署、Prometheus怎么配抓取。后面几章我就按这个顺序展开。2. 部署前先搞懂redis_exporter怎么走通数据链路部署redis exporter没那么玄乎但选错方式、配错参数后续排查会比较难受。这一章先把数据是怎么流的讲清楚再对比三种常见的部署方式你按场景选一种就行。2.1 一个请求进来数据是怎么流转的redis exporter默认监听在9121端口每次Prometheus来抓取默认15秒一次exporter就会执行一系列Redis命令把拿到的数据处理成指标。具体流程可以分成四步建立连接exporter根据配置的地址、密码、TLS证书和Redis实例建立TCP连接。连接方式支持redis:// 和 rediss:// 协议前缀如果Redis启用了TLS前缀要写对。采集数据exporter会执行INFO ALL、CLIENT LIST、CONFIG GET、SLOWLOG GET等命令。注意它拿到的不仅仅是INFO输出的那些东西CLIENT LIST能拿到每个连接的详细状态SLOWLOG能看到慢命令这些都是INFO里面没有的维度。格式转换拿到原始数据后exporter把Redis的文本格式解析成Prometheus指标格式。比如INFO里的used_memory: 123456会被解析成一个名为redis_memory_used_bytes的Gauge指标数值保持123456不变。等待抓取转换完的指标缓存在exporter进程内Prometheus通过HTTP请求拉走。整个交互是Pull模型不是Push所以exporter自己是不会主动把数据发给Prometheus的。理解这四步之后很多问题就迎刃而解了。比如你发现Grafana上只有点状数据没有连续曲线大概率是Prometheus的抓取间隔和exporter的响应时间不匹配如果某些指标永远是0可能是Redis版本不支持某个命令被exporter静默降级了。2.2 三种部署方式的选型对比redis exporter本身是Go语言编译的单个二进制文件部署极其方便。但不同环境下有不同最优解我把三种常见方式列在下面。部署方式适用场景优点缺点二进制直接跑物理机或虚拟机上的Redis部署最快资源占用最低进程守护和自愈要自己管Docker Compose开发环境、单机多实例配置清晰环境隔离需要维护镜像和网络Kubernetes DeploymentK8s集群内Redis弹性调度、滚动更新需要理解K8s网络模型二进制方式最直接。去GitHub Release页面下载对应平台的安装包解压后直接启动wget https://github.com/oliver006/redis_exporter/releases/download/v1.61.0/redis_exporter-v1.61.0.linux-amd64.tar.gz tar -zxvf redis_exporter-v1.61.0.linux-amd64.tar.gz cd redis_exporter-v1.61.0.linux-amd64 REDIS_ADDRredis://127.0.0.1:6379 REDIS_PASSWORD你的密码 ./redis_exporter启动后先别急着配Prometheus先用curl确认指标能正常拉取curl -s http://127.0.0.1:9121/metrics | grep -E redis_up|redis_memory_used_bytes看到redis_up 1说明exporter成功连上了Redisredis_memory_used_bytes这类指标也出来了链路就通了。Docker方式适合已经有容器化习惯的团队。一条命令就能起docker run -d --name redis-exporter \ -p 9121:9121 \ -e REDIS_ADDRredis://172.17.0.2:6379 \ oliver006/redis_exporter:latest我建议开发环境用这种方式干净利落不污染宿主机。但记得把--restartalways加上不然Docker守护进程重启后exporter不会自动拉起来。K8s方式是生产环境最常见的选择。redis exporter作为Deployment部署Prometheus通过Service发现来抓取。K8s下有个小技巧如果你只是监控K8s集群内的Redis可以不用给exporter单独配Service直接写Pod的annotations配合Prometheus的Pod注解发现机制它会自动找上来。apiVersion: apps/v1 kind: Deployment metadata: name: redis-exporter namespace: monitoring spec: replicas: 1 selector: matchLabels: app: redis-exporter template: metadata: annotations: prometheus.io/scrape: true prometheus.io/port: 9121 labels: app: redis-exporter spec: containers: - name: redis-exporter image: oliver006/redis_exporter:latest env: - name: REDIS_ADDR value: redis://redis-service:6379 ports: - containerPort: 9121选型没有标准答案我自己的习惯是开发环境用Docker测试和生产如果是虚拟机就二进制加systemd托管如果上了K8s就直接Deployment。核心思路是让exporter尽可能贴近Redis部署网络路径短稳定性高。3. 核心参数逐个拆解这些配置直接影响监控结果很多人用redis exporter就是配个地址和密码就完事了但真正把参数吃透之后能做的事情多很多。这一章我把高频使用的参数按功能分组拆开讲顺便说一下哪些参数是容易踩坑的。3.1 连接相关地址、密码、TLS先看最基本的几个连接参数REDIS_ADDRRedis实例地址支持逗号分隔多个地址格式如redis://127.0.0.1:6379,redis://127.0.0.1:6380。多实例场景可以共用一个exporter进程但我后面会讲为什么不太建议这么做。REDIS_PASSWORDRedis密码。如果密码里有特殊字符记得在URL里做URL编码或者用环境变量传入避免空格和#引起的解析问题。REDIS_TLS是否启用TLS设为true时地址前缀要改成rediss://。自签名证书环境下还需要配合REDIS_TLS_CA_CERT、REDIS_TLS_CERT、REDIS_TLS_PRIVATE_KEY这几个参数。REDIS_USERRedis 6.0以上支持ACL默认用户是default如果你创建了专门的monitor用户这里填用户名。如果你管理的Redis是在云上比如自建的云主机或者托管的Redis实例REDIS_ADDR一定要用能走内网的地址。我见过有人把公网地址填进去然后发现Prometheus抓取延迟特别高因为exporter到Redis的每次命令往返都要过公网监控本身的延迟比被监控对象的状态变化还夸张。3.2 采集逻辑默认姿势和check-keys的取舍redis exporter默认会采集所有以redis_前缀开头的指标涵盖内存、CPU、连接数、命令统计、持久化、复制等维度。如果你只是想快速搭一套基础监控什么都不用配默认采集姿势已经足够。但如果想监控某个具体key的长度或者某个key是否存在就需要用到REDIS_CHECK_KEYS参数。这个参数的格式是key的pattern支持glob风格的通配符。比如你想监控消息队列的积压情况队列key的pattern是queue:*REDIS_CHECK_KEYSqueue:* ./redis_exporterexporter会遍历匹配的key对每个key执行LLEN、HLEN、SCARD这类命令把结果输出成redis_key_length指标并带上db和key两个label。注意REDIS_CHECK_KEYS用起来要克制。如果Pattern写得太宽比如直接写*那等于要对Redis里所有key做一次SCAN加各种LEN操作在key数量很大的实例上这个采集动作本身就会拖慢Redis属于典型的监控反噬。还有个参数叫REDIS_CHECK_KEYS_BATCH_SIZE默认100。它控制exporter每批检查多少个key如果key数量多可以把批次调大减少命令轮次但每轮的时间会变长。我建议保持默认除非你很清楚自己在做什么。3.3 运行姿态多实例、日志、超时REDIS_EXPORTER_IS_AWS_ELASTICACHE如果监控的是AWS ElastiCache这个参数应该设为true它会开启Elasticache特有的指标采集。自建环境不要开。REDIS_EXPORTER_DEBUG设为true会输出详细的DEBUG日志排错很有用。正常运行时建议关闭不然日志量有点大。REDIS_EXPORTER_REDIS_TIMEOUTexporter和Redis通信的超时时间默认60秒。如果Redis负载很高INFO命令本身可能超过1秒这个超时留够空间就行不要设太小。REDIS_EXPORTER_WEB_LISTEN_ADDRESSexporter自身的监听地址默认0.0.0.0:9121。如果你只要本机Prometheus抓取改成127.0.0.1:9121更安全。除了环境变量所有这些参数也支持命令行flag方式比如--redis.addr--redis.password。两种方式等价我习惯用环境变量因为K8s里配置env比传参更自然。4. 看得懂的指标才算监控关键指标和告警要这么配exporter装好、指标也抓到了接下来就要面对一个实际问题那么多以redis_开头的指标哪些值得盯哪些看一眼就行这一章我按运维视角把指标分分类给出我认为最需要关注的几个以及对应的告警规则。4.1 内存和淘汰策略指标撑起Redis最重要的告警内存是Redis最核心的资源指标redis_memory_used_bytes直接对应INFO里的used_memory。这个值接近maxmemory时Redis会进入淘汰状态根据maxmemory-policy的配置决定是LRU淘汰还是拒绝写入。告警阈值不能直接按百分比算因为不同实例的maxmemory设置不一样。# 内存使用率假设maxmemory配置为8GB (redis_memory_used_bytes / 8589934592) * 100另外两个内存指标值得看redis_memory_max_bytesRedis能用的最大内存如果这个值为0说明没限制告警规则里要处理这种情况。redis_memory_fragmentation_ratio内存碎片率大于1.5说明碎片化严重可能是频繁修改大key导致的。内存碎片率这个指标我实际用过碎片率飙到2.x的时候Redis明明没存多少数据used_memory却居高不下。这时候重启Redis实例最直接或者调整activedefrag参数让Redis自己整理碎片。4.2 持久化与主从复制指标最容易出问题的环节持久化这块redis_rdb_changes_since_last_save这个指标很常用。它表示上次RDB快照之后有多少次写操作。如果这个值持续增长同时redis_rdb_last_bgsave_status是1表示成功0表示失败说明RDB一直在正常执行不用担心。最怕的是redis_rdb_last_bgsave_timestamp_seconds和当前时间差越来越大说明很久没有成功的RDB保存了数据安全就有隐患。主从复制的关键指标是redis_connected_slaves和redis_replication_connected_slaves。如果Redis节点配置了复制这两个值会持续波动说明主从连接不稳定。配合redis_master_link_up看主从通道是否确实断开。我遇到过一个典型的踩坑场景某个从库因为网络抖动和主库断连但由于断线重连的逻辑设置了比较长的超时从库和主库的数据差已经到了几个小时。如果只盯connected_slaves是发现不了的因为连接还在只是数据同步积压了。这时候要盯redis_master_repl_offset和redis_slave_repl_offset两者差值就是同步延迟的字节数。告警规则可以这么写# 主从复制延迟超过100MB就告警 abs(redis_master_repl_offset - redis_slave_repl_offset) 1048576004.3 客户端连接和命令统计定位性能瓶颈的关键redis_connected_clients是当前客户端连接数。这个值如果持续上涨而且接近maxclients说明应用层的连接池管理可能出了问题比如连接被泄漏了没有释放。结合redis_connected_clients_evicted因为超过maxclients而被拒绝的连接数一起看能很快判断是哪种情况。命令统计指标里有意思的是redis_commands_total它带上cmd这个label统计每种命令的执行次数。通过PromQL可以算慢命令占比、热点命令分布# 每秒执行次数Top5的命令 topk(5, rate(redis_commands_total[1m]))另一个和慢查询相关的指标是redis_slowlog_last_id它表示SLOWLOG最新的日志ID。如果这个值在快速跳动说明Redis正在大量执行超过慢查询阈值的命令此时性能多半已经出问题了。4.4 一套可以直接抄的告警规则Prometheus告警规则可以写成一个yml文件示例配置如下groups: - name: redis-exporter-alerts rules: - alert: Redis内存使用率过高 expr: (redis_memory_used_bytes / redis_memory_max_bytes) * 100 85 for: 5m labels: severity: warning annotations: summary: Redis实例内存使用率超过85% description: 实例 {{ $labels.instance }} 当前内存使用率 {{ $value }}% - alert: Redis主从复制延迟过大 expr: abs(redis_master_repl_offset - redis_slave_repl_offset) 104857600 for: 2m labels: severity: critical annotations: summary: Redis复制延迟超过100MB description: 实例 {{ $labels.instance }} 主从数据同步积压超过100MB告警阈值没有放之四海而皆准的还是得根据业务情况调。内存阈值85%对那种内存就是拿来缓存、淘汰策略是LRU的实例就太保守了它对90%以上也未必有影响。但如果是用Redis做复杂集合运算的内存超过80%就该高度重视因为新增数据可能直接触发OOM。5. 实战中的坑从密码认证到高并发这些我都踩过用redis exporter这些年遇到的坑不少。大部分问题不是exporter本身的问题而是监控系统和Redis的联动方式没想清楚。写几个真实的踩坑经历你遇到类似的可以少走弯路。5.1 Redis 6.0 ACL认证导致scrape全部失败Redis 6.0开始支持ACLAccess Control List如果运维为了安全把默认用户给禁了而exporter还在用老密码连接就会出现一个很诡异的现象exporter进程正常启动但Prometheus抓回来的所有指标全都没有值或者在普罗米修斯里看到redis_up跳变。原因是exporter连接Redis时默认用的用户名是default如果Redis把default用户禁掉了连接直接抛WRONGPASS。排查方法是看exporter日志ERR max number of clients reached不对这个错误是连接数问题。ACL失败时日志一般是ERR invalid password解决方式很简单用专门的监控账号代替default。在Redis里创建账号按照最小权限原则来ACL SETUSER redis_exporter on 你的强密码 all -admin ~* *然后在exporter里配置REDIS_USERredis_exporter和REDIS_PASSWORD你的强密码。这一步做对了后续无论Redis侧怎么改权限监控都不会受影响。5.2 采集频率太高把Redis连接池打满这是我自己踩的最深的一个坑。某次监控平台统一调整抓取频率把15秒改成5秒结果那天下午Redis突然出现大量连接拒绝的报错。查下来发现Prometheus每个实例配置了多个target每个target抓取时还会触发exporter多个并发TCP连接叠加起来瞬间连接数翻了好几倍。Redis的maxclients默认是10000一般不会打满但如果你的Redis实例本身链路就很多加上exporter引入的额外连接还是可能触顶。有两种解法方案A是给Prometheus单独开一个抓取配置降低抓取频率scrape_configs: - job_name: redis metrics_path: /metrics scrape_interval: 30s static_configs: - targets: [127.0.0.1:9121]方案B是给exporter起一个独立的Pod或进程和业务流量隔离。生产环境我倾向两个都做抓取频率保持30秒以上exporter单独部署一套避免因为监控系统自身的问题影响业务访问Redis。这个坑的底层逻辑是监控系统本身也会消耗被监控对象的能力采集频率、采集命令数量都要纳入容量评估。5.3 K8s环境下多实例的exporter管理在K8s里跑Redis Cluster时一个集群通常有6个节点。最省事的做法是一个exporter进程配6个地址用逗号分隔。但这样有个问题Prometheus抓一次会把6个实例的指标全部拉回来排错时候分不清哪个指标对应哪个节点label也乱。我更推荐的做法是一对一部署每个Redis节点配一个exporter容器通过StatefulSet编排exporter的地址指向本地回环的Redis实例这样指标往上送的时候Prometheus能通过pod标签或者instance标签精确区分出是哪个节点。StatefulSet ├── redis-0 exporter-0 (REDIS_ADDRredis://redis-0:6379) ├── redis-1 exporter-1 (REDIS_ADDRredis://redis-1:6379) └── redis-2 exporter-2 (REDIS_ADDRredis://redis-2:6379)这么做牺牲了一点资源多了几个轻量进程换来了指标的可区分性后续做节点维度告警、排错都方便很多。5.4 exporter自身不是免费的资源占用和性能影响redis exporter虽然是个轻量进程但它在采集过程中会对Redis执行额外命令还是有开销的。默认情况下它每轮采集会执行INFO ALL这个命令本身在实例很大时比如几万个key或者很多客户端连接会消耗几十毫秒的CPU时间如果抓取频率太快对高负载Redis是有影响的。还有一点容易忽略exporter默认还带--redis.include-command参数可以自定义要执行的命令。如果你需要采集某些自定义指标比如业务写入的自增计数器可以用这个参数。但加命令意味着每轮采集多一轮Redis往返命令写得不好比如用了KEYS反而帮了倒忙。我自己用下来监控Redis的key基数最好不要超过10万级超过后INFO和SCAN的开销开始变得明显。如果你管理的Redis超大建议考虑用Redis自带的latency monitor和memory doctor这类内部诊断工具来做补充不要把所有压力都压在exporter一轮轮的采集上。6. 最后分享一点个人的使用习惯把这些年用redis exporter攒下来的一些小习惯放在这里。谈不上教程就是纯经验分享。习惯一用systemd托管二进制进程时写好环境变量文件。别把密码直接写在启动命令里那样进程列表里都能看到。写一个/etc/redis_exporter.conf然后通过EnvironmentFile加载配置和代码分离维护也好做。REDIS_ADDRredis://127.0.0.1:6379 REDIS_PASSWORD你的强密码 REDIS_EXPORTER_WEB_LISTEN_ADDRESS0.0.0.0:9121习惯二监控指标分两层看。第一层是资源层内存、CPU、连接数这些告诉你Redis是不是还健康第二层是业务层缓存命中率、key积压数量、慢命令频率这些告诉你Redis在业务slo中的表现。资源层指标异常往往是业务层指标异常的原因两个维度要联合分析。结合redis缓存穿透的场景举个例子当缓存命中率指标可以用redis_keyspace_hits_total/redis_keyspace_hits_total redis_keyspace_misses_total算出来持续走低同时Redis整体QPS还在涨这就说明大量请求没命中缓存直接打到数据库了。这时候如果只看资源层指标你可能会去扩容Redis但真正的修复方案是去查热点key是不是被穿透了。习惯三告警一定要配for关键字。Prometheus告警规则里的for: 5m表示持续5分钟才触发告警。这个参数非常重要它能把瞬时的抖动过滤掉避免告警疲劳。Redis内存偶尔冲到90%然后又掉下来如果一看到超过阈值就告警夜班同事会被你折磨疯。redis exporter不是什么高精尖的东西它的价值在于把Redis这个每天都要用、但状态经常被忽视的组件纳入了统一的观测体系。和缓存穿透的治理一样——如果连缓存层有异常请求都看不见治理就永远只能靠事后救火谈不上主动维护。最后提醒一句exporter和Prometheus的版本尽量保持更新。这个项目虽然稳定但Redis新版本有时会调整内部命令的返回结构老版本exporter解析新格式可能出现指标缺失。隔一段时间去Release页面看看有更新就顺手升一下成本很低收益明确。
返回列表