返回首页

MySQL / Redis 常见故障排查速查清单

📅 创建于 2026-07-09 🔄 更新于 2026-07-09 📝 1587 字

MySQL / Redis 常见故障排查速查清单

来源:运维派 | 发布日期:2026-07-04

覆盖 MySQL 和 Redis 最常见的 20+ 种生产故障,每个故障按「现象 → 排查 → 根因 → 修复 → 验证」结构组织。适合值班 oncall、故障复盘、健康巡检时快速对号入座。

💡 本文是"速查清单/决策树"视角。MySQL 性能调优(慢查询/锁/死锁/索引/Buffer Pool)深度内容见 mysql-performance-config;Redis 内存优化(数据结构/TTL/淘汰/Bigkey/碎片)见 redis-memory-optimization;Redis 连接管理见 redis-connection-management

整体排查框架

无论是 MySQL 还是 Redis 故障:

告警 → 确认影响范围 → 收集关键指标 → 缩小范围 → 定位根因 → 修复 → 验证 → 复盘

关键原则:先止血,再排查。kill 进程前先记录 processlist,清理数据前先备份。不确定的命令先在测试环境验证。

核心排查工具速查

MySQL 用途 Redis 用途
SHOW PROCESSLIST 当前连接和 SQL INFO 全局信息(内存/连接/复制/持久化)
SHOW ENGINE INNODB STATUS 死锁/IO/Buffer Pool SLOWLOG GET 慢查询日志
SHOW SLAVE STATUS 主从复制状态 CLIENT LIST 当前所有客户端
performance_schema / sys 锁等待/IO/语句统计 MEMORY USAGE key 单个 key 内存占用
慢查询日志 + mysqldumpslow 慢 SQL 分析 redis-cli --bigkeys 大 key 扫描
pt-query-digest 慢 SQL 深度分析 LATENCY HISTORY 延迟事件历史
information_schema 元数据(表大小/索引) MEMORY DOCTOR 内存问题诊断

第一部分:MySQL 常见故障

故障 1:连接数耗尽

现象:应用报 ERROR 1040 (HY000): Too many connections

排查

SHOW VARIABLES LIKE 'max_connections';
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';

-- 按用户/主机聚合,找连接泄漏源
SELECT user, SUBSTRING_INDEX(host,':',1) AS client_ip, COUNT(*) AS cnt
FROM information_schema.processlist
GROUP BY user, client_ip ORDER BY cnt DESC LIMIT 20;

-- 查看空闲连接(可能连接泄漏)
SELECT id, user, host, db, command, time
FROM information_schema.processlist
WHERE command = 'Sleep' ORDER BY time DESC LIMIT 20;

根因判断:Threads_connected 高但 Threads_running 低 → 空闲连接堆积。Threads_running 也高 → 慢查询/锁等待阻塞。某 IP 异常高 → 该应用实例问题。

修复:紧急 SET GLOBAL max_connections = 2000;;短期 kill 空闲连接 + 调 wait_timeout;长期修复连接泄漏。

故障 2:主从复制延迟

现象Seconds_Behind_Master 持续增大或波动

排查

-- MySQL 5.7: SHOW SLAVE STATUS\G
-- MySQL 8.0+: SHOW REPLICA STATUS\G
-- 关注:Seconds_Behind_Master、IO/SQL 线程状态、Relay_Log_Space

-- 查看从库正在回放什么
SHOW PROCESSLIST;

-- 是否有锁等待阻塞回放
SELECT * FROM information_schema.innodb_trx;

根因:主库大事务 → 从库单线程回放慢;从库磁盘 IO 瓶颈(iostat 确认);从库查询锁住回放;并行复制未开启。

修复:开启并行复制(replica_parallel_type=LOGICAL_CLOCK);避免主库大事务,拆分为小批量;从库使用 SSD。

故障 3:慢查询拖垮系统

现象:CPU 飙高,大量查询超时

排查

-- 查看当前正在执行的慢 SQL
SELECT id, user, host, db, time, state, LEFT(info, 200) AS query
FROM information_schema.processlist
WHERE command != 'Sleep' AND time > 3 ORDER BY time DESC;
# 分析慢查询日志
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
pt-query-digest /var/log/mysql/slow.log --limit=20

修复:添加索引;优化 SQL(减少子查询、避免 SELECT *、合理分页);kill 超时 SQL(先确认影响);临时限流有问题接口。

故障 4:死锁

现象Deadlock found when trying to get lock; try restarting transaction

排查

SHOW ENGINE INNODB STATUS\G
-- 找到 LATEST DETECTED DEADLOCK 部分
-- 显示:参与死锁的两个事务 / 各自持有和等待的锁 / 被回滚的事务(victim)

-- 开启死锁日志记录到错误日志(MySQL 5.7.2+)
SET GLOBAL innodb_print_all_deadlocks = ON;

根因:两个事务以不同顺序更新同一组行;间隙锁冲突(RR 隔离级别下的范围查询);唯一索引冲突 + INSERT。

修复:统一加锁顺序(按主键顺序操作);减小事务粒度;考虑降级到 RC 隔离级别;应用层加重试。

故障 5:元数据锁等待(MDL Lock)

现象SHOW PROCESSLIST 显示大量 Waiting for table metadata lock

排查

-- 需要先开启 instrument
UPDATE performance_schema.setup_instruments
SET enabled = 'YES', timed = 'YES'
WHERE name = 'wait/lock/metadata/sql/mdl';

-- 查看 MDL 锁持有情况
SELECT * FROM performance_schema.metadata_locks
WHERE OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'your_table';

-- 查看长事务(可能持有 MDL 共享锁)
SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query
FROM information_schema.innodb_trx ORDER BY trx_started ASC;

根因:未提交的长事务持有 MDL 读锁 → DDL 无法获取写锁 → 后续所有查询排队。

修复:kill 持有 MDL 的长事务(先确认 innodb_trx.trx_rows_modified,大事务回滚耗时);DDL 使用 pt-online-schema-changegh-ost;大表 DDL 安排在低峰期。

故障 6:磁盘写满

现象:MySQL 无法写入,df -h 显示 100%

排查

df -h
du -sh /var/lib/mysql/* | sort -rh | head -20
ls -lh /var/lib/mysql/mysql-bin.*   # binlog 占用

常见根因:binlog 无过期时间持续堆积;大事务 undo log 膨胀(ibdata1 增长);慢查询大量临时文件;通用日志误开启。

修复

-- MySQL 8.0: 设置 binlog 7 天过期
SET GLOBAL binlog_expire_logs_seconds = 604800;
-- MySQL 5.7: SET GLOBAL expire_logs_days = 7;

-- 手动清理 binlog(确认从库已同步)
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);

⚠️ PURGE BINARY LOGS 不可逆。ibdata1 增大后不会自动缩小,只能逻辑导出导入重建。

故障 7:复制中断

现象:SQL 线程停止,Last_Error 不为空

错误码 含义 修复
1062 Duplicate entry 从库已有该数据 SET GLOBAL sql_slave_skip_counter = 1;(跳过后用 pt-table-checksum 校验)
1032 Can't find record 从库找不到要更新/删除的行 同上,跳过 + 校验
1236 binlog position error binlog 被清理或损坏 重建从库(xtrabackup/mysqldump)

故障 8:Buffer Pool 命中率低

现象:查询响应变慢,磁盘 IO 升高

排查

SHOW STATUS LIKE 'Innodb_buffer_pool_read_requests';  -- 逻辑读
SHOW STATUS LIKE 'Innodb_buffer_pool_reads';          -- 物理读
-- 命中率 = 1 - (reads / read_requests),正常应 > 99%

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW STATUS LIKE 'Innodb_buffer_pool_pages_free';

修复:调大 innodb_buffer_pool_size(建议物理内存 60%-80%);优化 SQL 避免全表扫描;用 innodb_old_blocks_time 保护热数据。

故障 9:临时表/排序溢出到磁盘

现象EXPLAIN 显示 Using temporary; Using filesort

排查

SHOW STATUS LIKE 'Created_tmp_disk_tables';
SHOW STATUS LIKE 'Created_tmp_tables';
-- 比率 > 10% 说明频繁溢出

SHOW VARIABLES LIKE 'tmp_table_size';
SHOW VARIABLES LIKE 'max_heap_table_size';

修复:调大 tmp_table_sizemax_heap_table_size(两者取较小值);优化 SQL 减少临时表;tmpdir 使用 SSD。

故障 10:大表 DDL 阻塞业务

现象:执行 ALTER TABLE 后该表所有查询阻塞(Waiting for table metadata lock

修复:使用在线 DDL 工具:

pt-online-schema-change --execute \
  --alter "ADD COLUMN status TINYINT DEFAULT 0" \
  D=mydb,t=mytable --host=127.0.0.1

# 或 gh-ost
gh-ost --host=127.0.0.1 --database=mydb --table=mytable \
  --alter="ADD COLUMN status TINYINT DEFAULT 0" --execute

⚠️ pt-oscgh-ost 都会产生额外 IO 和主从延迟,高峰期需设节流参数。

故障 11:字符集不一致导致索引失效

现象:JOIN 条件明明有索引但不走,EXPLAIN 显示全表扫描

原因:两表字段字符集不同(如 utf8mb4 vs utf8),JOIN 时发生隐式转换 → 索引失效。

修复:统一字段字符集:

ALTER TABLE table_b MODIFY COLUMN name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

故障 12:慢日志未轮转占满磁盘

排查

ls -lh $(mysql -N -e "SHOW VARIABLES LIKE 'slow_query_log_file'" | awk '{print $2}')

修复:配置 logrotate 定期轮转。


第二部分:Redis 常见故障

故障 13:内存耗尽(OOM)

现象:写入报 OOM command not allowed when used memory > 'maxmemory'

排查

redis-cli INFO memory | grep -E 'used_memory_human|maxmemory_human|maxmemory_policy'
redis-cli INFO stats | grep evicted_keys

修复:紧急调大 maxmemory;调整 maxmemory-policy(推荐 allkeys-lru);扫描并拆分/删除大 key;长期扩容或优化数据模型。

故障 14:大 Key 导致阻塞

现象:Redis 响应间歇性卡顿,CPU 出现尖峰

排查

redis-cli --bigkeys          # 按 key 数量维度
redis-cli --memkeys          # 按内存维度
redis-cli MEMORY USAGE <key> # 单个 key 内存

修复:拆分大 Hash/List/Set(按 hash tag 分片);用 UNLINK 替代 DEL(异步删除,Redis 4.0+);业务侧避免往单个 key 无限追加。

故障 15:慢查询

现象SLOWLOG 中有异常命令

排查

redis-cli SLOWLOG GET 20
redis-cli SLOWLOG LEN

常见慢命令:KEYS *(应替换为 SCAN)、HGETALL 大 Hash(应改为 HSCAN)、DEL 大 key(改为 UNLINK)、SORT 大集合。

故障 16:主从复制延迟/中断

现象INFO replication 显示 master_link_status:down 或 offset 持续落后

排查

redis-cli INFO replication
# 关注:role / connected_slaves / master_link_status / master_repl_offset

根因:主库写入量超过从库处理能力;网络带宽不足;从库正在做 RDB 持久化阻塞复制。

修复:在从库关闭 AOF/RDB(仅在从库做持久化由主库负责);调大 repl-backlog-size;使用 repl-diskless-sync(无盘复制)。

故障 17:Sentinel 频繁切换

现象:主从频繁切换,监控不断告警

排查

redis-cli -p 26379 SENTINEL MASTERS
redis-cli -p 26379 SENTINEL SENTINELS mymaster
# 检查 sentinel.conf 中 down-after-milliseconds 是否太敏感

修复:调大 down-after-milliseconds(建议 30000-60000ms);增加 Sentinel 实例数(≥3 个,奇数);检查网络是否存在间歇性丢包。

故障 18:内存碎片率高

现象used_memory_rss / used_memory > 1.5

排查

redis-cli INFO memory | grep mem_fragmentation_ratio

修复:Redis 4.0+ 开启 activedefrag yes;极端情况重启实例(注意持久化完整性)。

故障 19:RDB/AOF 持久化阻塞

现象:fork 期间 Redis 响应卡顿或暂时无响应

排查

redis-cli INFO stats | grep latest_fork_usec
# fork 耗时 > 1 秒即需关注
redis-cli INFO persistence | grep rdb_bgsave_in_progress

修复:控制单个 Redis 实例内存 < 10GB(降低 fork 开销);非必要不在从库做 RDB;AOF 使用 everysec 策略。

故障 20:连接数耗尽

现象:客户端报 ERR max number of clients reached

排查

redis-cli INFO clients | grep -E 'connected_clients|maxclients'
redis-cli CLIENT LIST | awk '{print $2}' | sort | uniq -c | sort -rn | head
# 看哪些 IP 连接最多

修复:调大 maxclients;设置 timeout 清理空闲连接(CONFIG SET timeout 300);修复客户端连接泄漏。

故障 21:缓存雪崩

现象:大量缓存同时过期,请求全部打到数据库

修复:设置 TTL 时加随机偏移:

import random
base_ttl = 3600  # 1小时
jitter = random.randint(0, 600)
redis.setex(key, base_ttl + jitter, value)

多级缓存(本地缓存 + Redis);热点 key 不设过期 + 后台定期刷新;限流/熔断保护后端。

故障 22:缓存穿透

现象:大量查询不存在的数据,每次都打到数据库

修复

# 方案一:缓存空值(短 TTL)
redis-cli SETEX "user:99999" 60 "NULL"

# 方案二:布隆过滤器(RedisBloom)
redis-cli BF.ADD exists_filter "user:1"
redis-cli BF.EXISTS exists_filter "user:99999"
# 返回 0 表示一定不存在,不查数据库

故障 23:缓存击穿

现象:某个热点 key 过期瞬间,大量请求同时打到数据库

修复——互斥锁模式:

def get_with_lock(key):
    value = r.get(key)
    if value:
        return value
    lock_key = f"lock:{key}"
    if r.set(lock_key, "1", nx=True, ex=10):
        try:
            value = query_from_db(key)
            r.setex(key, 3600, value)
        finally:
            r.delete(lock_key)
        return value
    else:
        time.sleep(0.1)
        return r.get(key)

或使用"逻辑过期"——缓存不设物理 TTL,value 中含逻辑过期时间,后台异步刷新。

故障排查决策树

MySQL

MySQL 异常
├── 连不上
│   ├── Too many connections → 故障 1
│   ├── Access denied → 权限问题
│   └── Can't connect → 网络/服务未启动
├── 查询慢
│   ├── 单条 SQL 慢 → 故障 3(慢查询)
│   ├── 整体变慢 → 故障 8(Buffer Pool)/ 故障 9(临时表溢出)
│   └── 间歇性慢 → 故障 4(死锁)/ 故障 5(MDL)
├── 数据不一致
│   ├── 主从延迟 → 故障 2
│   └── 复制中断 → 故障 7
└── 磁盘满 → 故障 6

Redis

Redis 异常
├── 连不上
│   ├── max clients reached → 故障 20
│   └── Connection refused → 服务未运行
├── 响应慢
│   ├── 单命令慢 → 故障 15(慢查询)
│   ├── 整体慢 → 故障 14(大 key)
│   └── 间歇性慢 → fork/AOF rewrite
├── 写入失败
│   └── OOM → 故障 13
├── 数据丢失
│   ├── 淘汰 → 故障 13
│   └── 穿透/雪崩/击穿 → 故障 21/22/23
└── 主从问题
    ├── 同步延迟/中断 → 故障 16
    └── 频繁切换 → 故障 17

常用命令速查

MySQL

-- 连接排查
SHOW PROCESSLIST;
SHOW STATUS LIKE 'Threads%';
SELECT * FROM sys.session;

-- 锁排查
SHOW ENGINE INNODB STATUS\G
SELECT * FROM sys.innodb_lock_waits;
SELECT * FROM information_schema.innodb_trx;

-- 复制排查
SHOW REPLICA STATUS\G    -- MySQL 8.0
SHOW SLAVE STATUS\G      -- MySQL 5.7

-- 性能排查
SHOW STATUS LIKE 'Innodb_buffer_pool%';
SHOW STATUS LIKE 'Created_tmp%';

Redis

redis-cli INFO                    # 全局状态
redis-cli INFO memory             # 内存详情
redis-cli INFO replication        # 复制状态
redis-cli SLOWLOG GET 20          # 慢查询
redis-cli CLIENT LIST             # 连接列表
redis-cli --bigkeys               # 大 key 扫描
redis-cli CLUSTER INFO            # 集群状态

生产环境注意事项

原则 说明
不在主库执行长查询 分析类查询走从库
备份策略 MySQL:全量备份 + 连续 binlog;Redis:根据容忍度选 RDB/AOF/混合
参数修改走流程 测试验证 → 变更单 → 低峰执行 → 观察 10-30 分钟
监控先行 操作前确认监控正常,操作后持续观察
操作有记录 所有操作记录到运维日志或工单
主从切换有预案 切换前确认从库追平,切换后检查应用连接
Redis 不做唯一存储 底层有持久化数据源兜底
每周巡检 max_connections 使用率、Buffer Pool 命中率、主从延迟、慢查询数、Redis 内存使用率、key 淘汰数

修复后验证

MySQLThreads_connected 回正常水位;Seconds_Behind_Master 趋于 0;SHOW ENGINE INNODB STATUS 无新增死锁;监控曲线(QPS/延迟/连接数)恢复基线。

Redisused_memory 在预期范围;master_link_status: upkeyspace_hits 比例恢复;SLOWLOG LEN 不再增长。

回滚方案

MySQL 参数修改回滚:SET GLOBAL xxx = <原始值>;(修改了 my.cnf 需重启)。

Redis:CONFIG SET 修改是临时的,重启恢复原始值(用了 CONFIG REWRITE 需恢复 redis.conf 备份)。

主从复制修复回滚——最终方案是重建从库(xtrabackup 全量备份 → 从库恢复 → 重新配置复制)。


关联页面

页面关联点
mysql-performance-configMySQL 性能调优深度指南(慢查询/锁/死锁/索引失效/深度分页/Buffer Pool)
redis-memory-optimizationRedis 内存优化完全指南(数据结构/TTL/淘汰策略/Bigkey/碎片治理)
redis-connection-managementRedis 连接管理与配置优化
mysql-replication-guideMySQL 主从复制完整指南
mysql-slow-query-case-studyMySQL 慢查询排查案例复盘(真实线上案例)
redis-ha-replication-sentinelRedis 高可用:主从复制 + Sentinel 哨兵模式
redis-persistence-strategyRedis 持久化策略(RDB/AOF/混合)
fullstack-performance-troubleshooting全栈性能排障入口(MySQL/Redis 在整体链路中的定位)