灯下哥谭 灯下哥谭
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

灯下哥谭

灯还亮着
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL

  • Redis

    • Redis 运维知识地图:从单机到 Cluster 排障
    • Redis 常用查询操作:五种数据类型速查 + 生产环境避坑
    • Redis 集群部署
    • Redis 大 key 分析:三条排查路径怎么选
    • Redis手动进行主从切换
    • Redis集群添加节点之后数据重新均匀分配
    • Redis槽位slot解读
    • Redis Cluster 新增节点 slot 迁移卡住:"open slots" 故障复盘
    • Redis集群的创建、剔除节点与新增节点操作过程
    • Redis配置文件解读
    • redis cluster压测
    • Redis 慢查询告警与抓包分析排障脚本
      • 1. 慢查询告警脚本
      • 2. 抓包分析脚本
        • 2.1 抓包命令
        • 2.2 使用 redis-faina.py 分析
        • 2.3 抓包的代价与限制
      • 3. 为什么 slowlog + 抓包需要配合使用
        • 3.1 slowlog 的单位是微秒不是毫秒
        • 3.2 slowlog-max-len 只是缓冲区大小
        • 3.3 slowlog 只记录命令执行耗时
        • 3.4 MONITOR 命令的坑
      • 4. 验证:脚本部署完怎么确认真的在工作
        • 4.1 验证慢查询告警链路
        • 4.2 验证抓包脚本
      • 5. 坑与边界
      • Agent 可直接解析的元数据块
    • Redis 的可用内存过高时的自动驱逐 key 策略详解
  • 高性能KV

  • TiDB

  • Elasticsearch

  • 数据管道

  • 其他数据库

  • 数据库
  • Redis
灯下哥谭
2023-01-15
目录

Redis 慢查询告警与抓包分析排障脚本原创

下面这个脚本定期读取 Redis 的 SLOWLOG,把超过阈值的慢命令整理后推送告警,适合挂在定时任务里做常态巡检。核心逻辑是记录上次处理过的慢日志 id,避免同一条重复告警。

在实际生产环境中,慢查询告警只能看到"命令执行慢",但真正拖慢请求的原因可能是:网络传输慢(大 value 在客户端和服务端之间来回传输的时间,不计入执行耗时)、排队等待(Redis 主线程被其他命令阻塞)、或 客户端本身的问题(请求发出去很久才收到响应)。这些信息 slowlog 看不到,必须靠抓包来补位。慢查询告警和抓包分析是同一件事的两个时间尺度——告警做常态监控,抓包做现场诊断。

版本说明

本文写于 2023-01,2026-09 复核。
Redis 协议(RESP)抓包分析方法未变;如集群已启用 RESP3 协议,部分命令的响应格式会有差异,脚本解析逻辑需相应调整。Slowlog 相关参数在 Redis 各个版本中保持稳定。

# 1. 慢查询告警脚本

redis_alarm.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import redis
import sys
import time
import os
import configparser
import requests
import json


def push_telegram(msg):
    request_header = {"content-type": "application/json; charset=UTF-8", "Authorization": "<YOUR_BOT_TOKEN>"}
    push_url = "<YOUR_PUSH_URL>"

    push_data = {"targetname": "<YOUR_TARGET_NAME>", "text": msg}
    push_data = json.dumps(push_data)
    requests.post(url=push_url, headers=request_header, data=push_data, verify=False)


names = {}
hosts = ["<PUBLIC_IP>", "<PUBLIC_IP>", "<PUBLIC_IP>"]

ports = {"<PUBLIC_IP>": [8001, 9001, 9002, 8002], "<PUBLIC_IP>": [8001, 8002, 9001, 9002], "<PUBLIC_IP>": [8001, 8002, 9001, 9002]}
# 获取文件的当前路径(绝对路径)
cur_path = os.path.dirname(os.path.realpath(__file__))
config_path = os.path.join(cur_path, "config.conf")
conf = configparser.ConfigParser()
conf.read(config_path)

for host in hosts:
    for port in ports[host]:
        names["max_" + host + "_" + str(port)] = conf.get("slowlog", "max_" + host + "_" + str(port))


print(names)
while True:
    start_time = time.perf_counter()
    for host in hosts:
        tmpMax = 0
        for port in ports[host]:
            pool = redis.ConnectionPool(host=host, port=port, password="<YOUR_REDIS_PASSWORD>", decode_responses=False)
            r = redis.Redis(connection_pool=pool)
            tList = r.slowlog_get(num=500)
            tmpMax = int(names["max_" + host + "_" + str(port)])
            while len(tList) > 0:
                slowContent = tList.pop()
                if slowContent["id"] > tmpMax:
                    errmsg = "redis集群主机:{}端口:{}发生慢查询\n执行时间:{}\n执行耗时:{}ms\n执行语句:{}\n客户端ip:{}".format(
                        host, port, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(slowContent["start_time"])), slowContent["duration"] / 1000, slowContent["command"], slowContent["client_address"]
                    )
                    names["max_" + host + "_" + str(port)] = slowContent["id"]
                    if (slowContent["duration"] / 1000) >= 20:
                        try:
                            push_telegram(errmsg)
                        except Exception as e:
                            print("An exception occurred:", e)

                    with open("check_rediscluster.log", "a+") as file_obj:
                        file_obj.write(errmsg)
                    tmpMax = int(slowContent["id"])
            r.close()
            conf.set("slowlog", "max_" + host + "_" + str(port), str(tmpMax))
            with open("config.conf", "w+") as f:
                conf.write(f)
            tmpMax = 0
    end_time = time.perf_counter()
    print("Calculation takes {} seconds".format(end_time - start_time))
    time.sleep(600)
    print("sleep over")

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

config.conf 配置文件用于记录当前记录已发送慢语句的数据统计,下次从该点往下加1,初始位置从1起

[slowlog]
max_<PUBLIC_IP>_8001 = 1
max_<PUBLIC_IP>_8002 = 1
max_<PUBLIC_IP>_9001 = 1
max_<PUBLIC_IP>_9002 = 1
max_<PUBLIC_IP>_9002 = 1
max_<PUBLIC_IP>_9001 = 1
max_<PUBLIC_IP>_8002 = 1
max_<PUBLIC_IP>_9001 = 1
max_<PUBLIC_IP>_8001 = 1
max_<PUBLIC_IP>_8001 = 1
max_<PUBLIC_IP>_9002 = 1
max_<PUBLIC_IP>_8002 = 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14

该脚本里用到了redis包

默认pip3下载的版本较低,使用该版本安装redis-4.5.5

wget https://files.pythonhosted.org/packages/53/30/128c5599bc3fa61488866be0228326b3e486be34480126f70e572043adf8/redis-4.5.5.tar.gz

tar zxvf redis-4.5.5.tar.gz
cd redis-4.5.5/
python3 setup.py install
1
2
3
4
5

使用方法

python3  redis_alarm.py
1

systemctl 启动

[Unit]
Description=redisalarm
After=network.target

[Service]
Type=simple
PIDFile=/var/run/redisalarm.pid
WorkingDirectory=/data/script/
ExecStart=python3 /data/script/redis_alarm.py
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2. 抓包分析脚本

现场诊断时,如果 slowlog 告警触发但看不出明显原因(比如执行时间只有 20ms 刚过阈值,但客户端反馈"很慢"),就需要抓包看真实的消息流动。

redis-faina.py 点击下载 (opens new window)

# 2.1 抓包命令

# 在 Redis 服务器上执行,用 tcpdump 抓取 6379 端口的流量,写入日志文件
tcpdump -i eth0 port 6379 -s 0 -w /tmp/redis-capture.pcap &

# 或者用 redis-cli monitor 方式(注意:生产环境慎用,会显著拖慢实例)
redis-cli -h <REDIS_HOST> -p <REDIS_PORT> -a <REDIS_PASSWORD> -c monitor | head -n 99999 >> /tmp/1201-redis.log
1
2
3
4
5

# 2.2 使用 redis-faina.py 分析

python redis-faina.py /tmp/1201-redis.log

# 输出示例
Overall Stats
========================================
Lines Processed  	99999
Commands/Sec     	9302.46

Top Prefixes
========================================
spring         	26850	(26.85%)
blacklist      	21755	(21.76%)
agentstatus    	15040	(15.04%)
agentuser      	12378	(12.38%)

Top Keys
========================================
spring:session:expirations:1638353760000   	7075	(7.08%)
topic_agent                                	3984	(3.98%)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2.3 抓包的代价与限制

  • 生产环境限时限量:在业务高峰期抓包,tcpdump 本身会消耗 CPU 和内存;如果磁盘 I/O 跟不上,抓包文件会快速膨胀甚至打满磁盘。建议用 -G 参数限制抓包时长(如 -G 60 表示 60 秒后自动停止),用 -C 限制文件大小(如 -C 100 表示 100MB 后轮转)。

  • -s 截断长度影响:tcpdump -s 0 抓完整包,但在还原命令时,如果 value 很大,redis-faina.py 可能只能看到部分内容。分析大 value 相关问题时,需要结合 INFO 命令看客户端的 resp 版本或直接看十六进制。


# 3. 为什么 slowlog + 抓包需要配合使用

# 3.1 slowlog 的单位是微秒不是毫秒

slowlog-log-slower-than 的值是微秒(μs),不是毫秒(ms)。这是最常见的配置事故:设成 1000 以为记录"超过 1 秒"的查询,实际上只记录超过 1 毫秒的查询,瞬间触发大量日志。

# 查看当前阈值(单位:微秒)
CONFIG GET slowlog-log-slower-than

# 设成 10000 微秒 = 10 毫秒
CONFIG SET slowlog-log-slower-than 10000
1
2
3
4
5

# 3.2 slowlog-max-len 只是缓冲区大小

这个参数控制慢查询日志的最大条数,不是时间范围。它是一个环形缓冲区,新记录覆盖最旧的。设得太小会导致慢查询在环形 buffer 里还没被脚本读走就被覆盖;设得太大则消耗内存。

# 查看当前最大条数
CONFIG GET slowlog-max-len

# 设为 10000 条
CONFIG SET slowlog-max-len 10000
1
2
3
4
5

# 3.3 slowlog 只记录命令执行耗时

这是 slowlog 最大的盲区:不包含网络传输时间和排队等待时间。

  • 网络传输:大 value 从 Redis 到客户端需要时间(比如一个 10MB 的 string,网卡传输可能耗时 50ms),这 50ms 不在 slowlog 里体现
  • 排队等待:如果 Redis 主线程正在执行一个耗时命令,后面的命令会排队,这个排队时间也不计入单个命令的执行耗时

所以"slowlog 干净"不等于"客户端不慢"——这正是抓包的价值所在。

# 3.4 MONITOR 命令的坑

有人想用 redis-cli MONITOR 代替抓包,这是生产环境的坑。MONITOR 会把每个命令实时输出到连接里,对 Redis 实例的性能影响非常大(会显著拖慢主线程),生产环境绝对不要用。抓包是旁路采集,MONITOR 是请求处理的一部分,两者对性能的影响不是一个量级。


# 4. 验证:脚本部署完怎么确认真的在工作

# 4.1 验证慢查询告警链路

  1. 模拟慢查询:

    CONFIG SET slowlog-log-slower-than 1000   # 设成 1000 微秒 = 1 毫秒
    DEBUG SLEEP 0.1                            # 故意沉睡 100 毫秒
    
    1
    2
  2. 检查 slowlog 有记录:

    SLOWLOG GET 1
    
    1

    应该有新记录,duration 显示约 100000 微秒。

  3. 检查脚本输出: 运行脚本,观察日志或 Telegram/企微推送,应该能看到这条慢查询被捕获。

  4. 验证递增记录: 检查 config.conf,对应节点的 max_<host>_<port> 应该已经更新为刚才 slowlog 的 id。

# 4.2 验证抓包脚本

  1. 检查抓包文件有内容:

    tcpdump -r /tmp/redis-capture.pcap | head -n 10
    
    1

    或者如果用的是 redis-cli monitor 方式:

    ls -lh /tmp/1201-redis.log
    
    1
  2. 运行分析脚本:

    python redis-faina.py /tmp/1201-redis.log
    
    1

    应该有命令统计输出,如果没有,说明抓到的数据为空或格式不对。

  3. 确认脚本在生成期间 Redis 响应正常:抓包时顺带观察 redis-cli PING 的响应时间,确认抓包没有显著拖慢实例。


# 5. 坑与边界

  1. slowlog 是内存里的环形队列,重启即失:slowlog 数据存在 Redis 内存中,没有持久化。Redis 重启后 slowlog 会清空,id 归零。脚本里的 last_id 可能远大于新产生的 id,导致漏报。解决:启动脚本时检测 Redis 启动时间,或把 last_id 重置为 0。

  2. slowlog 满环覆盖导致漏告:如果慢查询产生速度超过脚本检查频率(默认 600 秒一轮询),部分记录会被环形缓冲区覆盖而漏报。建议把 slowlog-max-len 设大(如 10000),或缩短脚本检查间隔。

  3. config.conf 并发写冲突:如果脚本多实例运行,或手动编辑配置文件时脚本恰好在写,可能导致文件损坏。建议用文件锁(flock)保护写操作,或把状态存到 Redis 本身。

  4. MONITOR 命令会显著拖慢实例:不要用 MONITOR 代替抓包,它是请求处理路径的一部分,会阻塞主线程。抓包是旁路采集,对业务影响可控。

  5. 抓包脚本跑在高并发实例上要限时限量:tcpdump 本身消耗 CPU 和 I/O,生产环境务必加 -G(时间限制)和 -C(文件大小限制)参数,否则磁盘会被打满。

  6. slowlog-log-slower-than 单位是微秒:设值时注意量级差异,1000 = 1 毫秒,不是 1 秒。


# Agent 可直接解析的元数据块

{
  "runbook": {
    "task": "redis-slowlog-and-pcap-troubleshooting",
    "permalinks": ["/pages/xxxsd2/"],
    "category": "database/Redis",
    "tags": ["redis", "slowlog", "troubleshooting", "pcap", "monitoring"],
    "redis_versions": ["5.0", "6.0", "7.0"],
    "verified_date": "2026-09"
  }
}
1
2
3
4
5
6
7
8
9
10
#可观测性#Redis
上次更新: 9/11/2026

← redis cluster压测 Redis 的可用内存过高时的自动驱逐 key 策略详解→

最近更新
01
DeepSeek Harness 实战 06|学习笔记:插件、工具、技能不在同一个维度上 原创
09-11
02
DeepSeek Harness 实战 05|让两个编码 Agent 共用一份长期记忆 原创
09-09
03
DeepSeek Harness 实战 04|学习笔记:从「已知限制」里读出三处设计张力 原创
09-08
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式