CentOS环境下MySQL数据库故障排查指南
本文旨在帮助运维和DBA工程师在CentOS操作系统下,对MySQL数据库进行系统化、全面的故障排查。文章涵盖MySQL核心架构原理、常见故障类型、日志分析、性能监控、参数优化、脚本实用示例等,以确保在生产环境中能够快速定位和解决问题。
目录
-
- 软件环境及版本
- 存储引擎原理概述
- 关键目录与文件说明
-
- 错误日志(error log)
- 查询日志(general log)
- 慢查询日志(slow query log)
- 系统日志(systemd & journal)
- 常用命令与脚本
-
- CPU与内存
- 磁盘I/O与文件系统
- 网络状况
-
- 服务无法启动
- 连接失败与超时
- 死锁与锁等待
- 查询性能下降
- 复制(Replication)故障
- 事务回滚与崩溃恢复
-
- innodb_buffer_pool_size
- innodb_log_file_size
- max_connections
- query_cache
- tmp_table_size & max_heap_table_size
-
- Prometheus + Grafana整合
- 常用指标阈值设置
- 自动化告警脚本示例
-
- 案例一:磁盘满导致MySQL崩溃
- 案例二:慢查询引起服务阻塞
- 案例三:主从复制延迟
前言
在高可用、海量数据的生产环境中,MySQL作为常见的关系型数据库,承担着核心业务读写请求。然而,因应用访问压力、配置不当或操作失误等原因,MySQL常出现服务中断、性能瓶颈等故障。CentOS作为Linux发行版的主流服务器操作系统,对MySQL的安装与维护具有广泛应用价值。深入理解MySQL在CentOS上的运行原理及排查方法,对于保障业务稳定至关重要。
本文基于MySQL 5.7/8.0与CentOS 7/8环境,结合实战经验,提供系统化、流程化的故障排查指南,并附带实用脚本与原理解读,帮助读者快速定位并解决各类故障。全文约6000字,涵盖从环境准备到案例分析的全流程。
MySQL在CentOS上的部署架构
软件环境及版本
# 查看OS版本
cat /etc/centos-release
# 查看内核版本
tuname -r
# 查看MySQL版本
mysql -V
- CentOS 7.9 / 8.4
- 内核版本 3.x / 4.x
- MySQL 5.7.38 / 8.0.33
- 文件系统:XFS 或 EXT4
存储引擎原理概述
MySQL主要存储引擎:InnoDB 与 MyISAM。
- InnoDB:事务型、支持行级锁、MVCC(多版本并发控制)、崩溃恢复。
- MyISAM:非事务型、仅表级锁、无崩溃恢复。
InnoDB的关键机制:
- 缓冲池(Buffer Pool):缓存数据页与索引页,减少I/O。
innodb_buffer_pool_size
设置原则为可用内存的70%-80%。 - 重做日志(Redo Log):顺序写入,保证事务持久性,重启时用于数据恢复。受
innodb_log_file_size
限制。 - 撤销日志(Undo Log):MVCC多版本控制实现长事务快照,位于
undo
表空间。 - 脏页刷新(Flush):后台IO线程将脏页异步写入磁盘,避免事务长时间阻塞。
关键目录与文件说明
路径 | 说明 |
---|---|
/var/lib/mysql | 默认数据目录 |
/etc/my.cnf | 主配置文件 |
/var/log/mysqld.log | 错误日志 |
/var/log/mysql/mysql.log | 通用查询日志 (若开启) |
/var/log/mysql/mysql-slow.log | 慢查询日志 (若开启) |
/var/run/mysqld | 存放PID文件 |
故障分类与优先级
- 严重故障 (P0/P1):服务不可用、数据损坏、主从强一致性中断。
- 重度故障 (P2):性能严重下降、主从复制超时或长时间延迟。
- 中度故障 (P3):偶发慢查询、部分功能异常。
- 轻度问题 (P4):日志告警、警告信息、监控阈值报警。
实际排查时,需结合业务SLA与服务级别协议,优先处理P0/P1故障,确保服务恢复。
日志分析与常用工具
错误日志(error log)
错误日志记录MySQL启动、关闭、运行时的异常和警告信息。
# 查看最新日志
tail -n 100 /var/log/mysqld.log
# 持续监控日志变化
tail -f /var/log/mysqld.log
常见错误:
InnoDB: Error: log file ./ib_logfile0 is of different size
:重做日志大小变化,需按步骤安全重建。Can't lock method\
pfs_memory_table_init`: 权限或SELinux导致启动失败。
查询日志(general log)
# my.cnf
[mysqld]
general_log=1
general_log_file=/var/log/mysql/mysql.log
实时记录所有SQL请求,便于审计与排查频繁连接。
慢查询日志(slow query log)
[mysqld]
slow_query_log=ON
slow_query_log_file=/var/log/mysql/mysql-slow.log
long_query_time=1 # 单位秒
log_queries_not_using_indexes=1
使用pt-query-digest
分辨最耗时的SQL语句:
pt-query-digest /var/log/mysql/mysql-slow.log > slow_report.txt
系统日志(systemd & journal)
# 查看MySQL单元日志
ojournalctl -u mysqld -n 200
常用命令与脚本
# 查看当前连接数
mysql> SHOW GLOBAL STATUS LIKE 'Threads_connected';
# 查看InnoDB状态
mysql> SHOW ENGINE INNODB STATUS\G;
# 检查表状态
mysql> CHECK TABLE db_name.table_name;
资源层面故障排查
CPU与内存
采用top
, htop
, vmstat
监控CPU与内存使用:
vmstat 2 10
重点关注:
- CPU使用中
wa
比例(I/O等待) si
/so
(Swap进出)
若内存飙高导致Swap,建议调大innodb_buffer_pool_size
或减少查询并增加物理内存。
磁盘I/O与文件系统
通过iostat -xz 2 5
查看磁盘I/O:
# 安装sysstat
yum install sysstat -y
iostat -xz 2 5
关注:
%util
接近100%await
与svctm
若I/O瓶颈,可考虑:
- 切换到性能更好的SSD
- 优化InnoDB刷脏策略:
innodb_flush_neighbors=0
网络状况
利用ping
, netstat
, ss
检测网络状况:
ping database_host -c 10
ss -tnp | grep mysqld
若出现大量TIME_WAIT
或网络丢包,需检查网络链路及 MTU 设置。
MySQL层面故障排查
服务无法启动
-
配置文件错误
- 检查
/etc/my.cnf
以及/etc/my.cnf.d/
下所有包含.cnf
的文件,确保没有语法错误。
mysqld --help --verbose | grep -A1 "Default options"
- 常见因多写或少写分号、方括号不匹配导致的启动失败,需逐行排查。
- 检查
-
权限与 SELinux
-
确保 MySQL 数据目录(默认
/var/lib/mysql
)归属mysql:mysql
并拥有 700 权限:chown -R mysql:mysql /var/lib/mysql chmod -R 700 /var/lib/mysql
-
如果启用了 SELinux,需要设置正确的安全上下文:
restorecon -R /var/lib/mysql sestatus # 查看当前 SELinux 模式
-
临时关闭 SELinux 进行验证:
setenforce 0 systemctl restart mysqld
-
-
端口冲突
-
默认监听 3306,使用
ss
或netstat
查看是否被其他服务占用:ss -tnlp | grep 3306
-
如被占用,可修改
my.cnf
中的port
参数或停止冲突服务。
-
-
InnoDB 重做日志文件大小变化
-
修改了
innodb_log_file_size
后,必须在关机状态下删除老的ib_logfile0
/ib_logfile1
,否则因大小不一致启动失败:systemctl stop mysqld mv /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile0.bak mv /var/lib/mysql/ib_logfile1 /var/lib/mysql/ib_logfile1.bak systemctl start mysqld
-
连接失败与超时
-
主机绑定与防火墙
-
在
my.cnf
中检查bind-address
,确保监听在正确的网卡或0.0.0.0
。 -
放通防火墙端口:
firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload
-
-
用户授权
-
查看当前用户及主机范围:
SELECT host, user FROM mysql.user;
-
扩展授权到任意主机(慎用)或指定网段:
GRANT ALL ON db.* TO 'user'@'%' IDENTIFIED BY 'password'; FLUSH PRIVILEGES;
-
-
连接数限制
-
查看最大连接数及当前使用峰值:
SHOW VARIABLES LIKE 'max_connections'; SHOW GLOBAL STATUS LIKE 'Max_used_connections';
-
如峰值接近上限,可适当提升
max_connections
,但需关注内存消耗。
-
-
超时参数
-
过短的
wait_timeout
、interactive_timeout
或connect_timeout
会导致连接断开:SHOW VARIABLES LIKE '%timeout%'; SET GLOBAL wait_timeout=300; SET GLOBAL connect_timeout=10;
-
死锁与锁等待
-
检测死锁
-
在 InnoDB 状态输出中查找最新死锁信息:
SHOW ENGINE INNODB STATUS\G;
-
“LATEST DETECTED DEADLOCK” 段落会展示涉及的事务、SQL 语句及等待资源。
-
-
锁等待监控
-
在
performance_schema
中查看当前等待锁:SELECT EVENT_ID, THREAD_ID, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_MODE FROM performance_schema.data_locks WHERE LOCK_STATUS = 'GRANTED' OR LOCK_STATUS = 'PENDING';
-
-
优化建议
- 将大事务拆分为多个小事务,避免长事务占用太多 undo 空间。
- 为经常用作查询条件的列建立合适索引,减少全表扫描锁时间。
- 在应用层面对事务冲突进行重试,结合指数退避策略降低锁等待概率。
查询性能下降
-
慢查询日志分析
-
通过
pt-query-digest
生成报告,找出最耗时、最频繁执行的 SQL:pt-query-digest /var/log/mysql/mysql-slow.log > slow_report.txt
-
-
执行计划检查
-
对热点 SQL 使用
EXPLAIN
,确认索引命中率及扫描量:EXPLAIN SELECT * FROM orders WHERE user_id = 123;
-
-
常见索引失效场景
- 在索引列上应用函数(如
DATE(col)
)会导致全表扫描。 - 隐式类型转换(
varchar
与int
比较)失去索引。 - 前缀模糊查询(
LIKE '%keyword'
)无法使用 B-tree 索引。
- 在索引列上应用函数(如
-
参数微调
- 调整
innodb_buffer_pool_size
、tmp_table_size
、join_buffer_size
等内存相关参数,确保大事务与排序操作能在内存中完成,减少磁盘临时表生成。
- 调整
复制(Replication)故障
-
主库状态检查
SHOW MASTER STATUS;
-
从库状态检查
SHOW SLAVE STATUS\G;
- 关注
Seconds_Behind_Master
、Last_SQL_Error
、Last_IO_Error
。
- 关注
-
常见错误及处理
-
Error 1236 (“Could not find first log file”): 通常因主库 binlog 已清理,从库位置指向已删除日志。需在从库上执行
CHANGE MASTER TO MASTER_LOG_FILE='当前存在的日志', MASTER_LOG_POS=xxx;
并重启复制。 -
Duplicate entry: 因数据不一致造成,若确认可跳过错误,执行:
STOP SLAVE; SET GLOBAL sql_slave_skip_counter=1; START SLAVE;
-
-
主从恢复
- 在从库清空或重新初始化后,可通过 mysqldump 或 xtrabackup 重新全量复制,并设置合适的
master_log_file
、master_log_pos
继续增量。
- 在从库清空或重新初始化后,可通过 mysqldump 或 xtrabackup 重新全量复制,并设置合适的
事务回滚与崩溃恢复
-
InnoDB 自动恢复
- InnoDB 在崩溃重启时会自动使用 redo log、undo log 完成崩溃恢复,无需人工干预,日志输出中会有
InnoDB: Starting crash recovery...
记录。
- InnoDB 在崩溃重启时会自动使用 redo log、undo log 完成崩溃恢复,无需人工干预,日志输出中会有
-
手动恢复历史操作
-
如果需要回放指定时间段的操作,可使用
mysqlbinlog
从 binlog 重放:mysqlbinlog --start-datetime="2025-05-01 00:00:00" /var/lib/mysql/mysql-bin.00000* \ | mysql -uroot -p
-
性能优化与参数调优
innodb_buffer_pool_size
-
建议设置为物理内存的 70%–80%,存储热点数据与索引,减少磁盘 I/O。
-
可动态扩容(MySQL 5.7+):
SET GLOBAL innodb_buffer_pool_size = 8 * 1024 * 1024 * 1024; -- 8GB
innodb_log_file_size
- 重做日志文件过小会导致频繁 checkpoint;过大则重启恢复时间过长。
- 总重做日志大小(
innodb_log_file_size × innodb_log_files_in_group
)建议为 buffer pool 的 25%。
max_connections
- 根据业务并发峰值设置,监控
Max_used_connections
,保持留有余量。 - 高
max_connections
会带来更多线程内存开销,需权衡。
query_cache
- MySQL 5.7 默认关闭,若读多写少,可小范围开启,设置
query_cache_size
与query_cache_limit
。 - 注意高并发下 query cache 可能带来锁竞争。
tmp_table_size & max_heap_table_size
- 控制内存临时表最大尺寸,默认 16MB;复杂查询建议提升至 64MB 或以上,避免磁盘临时表。
- 可通过
Created_tmp_disk_tables
与Created_tmp_tables
对比监控临时表使用类型。
监控与告警实践
Prometheus + Grafana 整合
-
安装 mysqld_exporter
yum install prometheus-mysqld-exporter -y systemctl enable --now prometheus-mysqld-exporter
-
Prometheus 配置
- job_name: "mysql" static_configs: - targets: ["db1.example.com:9104", "db2.example.com:9104"] metrics_path: /metrics
-
Grafana 仪表盘
- 导入官方 MySQL dashboard ID(如 7362),即可监控 QPS、连接数、Buffer Pool 命中率、锁等待、复制延迟等关键指标。
告警阈值示例
指标 | 阈值 | 说明 |
---|---|---|
Threads_connected | > 80% max_conn | 连接数接近极限时告警 |
Innodb_buffer_pool_usage | > 90% | Buffer Pool 使用过高 |
Innodb_row_lock_waits/s | > 50/s | 高频锁等待需优化 SQL |
Replication Lag (秒) | > 1s | 主从延迟超 1s |
Created_tmp_disk_tables/s | > 5/s | 太多磁盘临时表 |
自动化告警脚本(Bash)
#!/bin/bash
# 检查 replication lag
LAG=$(mysql -uroot -p'pwd' -e "SHOW SLAVE STATUS\G" | awk '/Seconds_Behind_Master/ {print $2}')
if [ "$LAG" -gt 5 ]; then
echo "Replication lag is ${LAG}s" | mail -s "MySQL Replication Alert" dba-team@example.com
fi
案例解析
案例一:磁盘满导致 MySQL 崩溃
- 现象:
ERROR 1037 (HY000): Sort aborted
、No space left on device
- 排查:
df -h
显示/var/lib/mysql
分区使用率 100%。 - 处理:删除过期备份与日志文件;扩容或挂载新磁盘;重启服务。
- 预防:配合
logrotate
管理 MySQL 日志,并设置磁盘使用告警。
案例二:慢查询引起服务阻塞
- 现象:应用响应延迟、
Threads_running
常驻高位。 - 排查:分析慢查询日志,发现某条关联多表的聚合查询耗时 5s。
- 优化:添加联合索引、拆分多表 JOIN 改为分步查询。
- 结果:该查询由 5s 降至 200ms;整体 QPS 提升 30%,响应 95% 百分位从 500ms 降至 120ms。
案例三:主从复制延迟
-
现象:
Seconds_Behind_Master
持续 >10s,业务读从库时数据不及时。 -
排查:网络抖动、从库 IO/SQL 线程阻塞、主库写入压力过大。
-
处理:
- 提升从库
slave_net_timeout
; - 主库开启异步提交减少同步阻塞;
- 分库分表降低写入压力;
- 提升从库
-
结果:延迟稳定 <1s,读从体验良好。
总结与建议
-
结构化排查流程
- 先从资源层面(CPU/内存/磁盘/网络)排查,再聚焦 MySQL 服务及 SQL 层面。
-
完善日志与监控
- 全面开启错误日志、慢查询日志,并使用 Prometheus/Grafana 实时透视指标。
-
定期故障演练
- 针对常见 P0/P1 故障做演练,确保切实掌握恢复操作。
-
持续性能优化
- 随业务增长定期评估参数、索引和架构,保持系统高效稳定。
附录:常用脚本汇总
# 导出 InnoDB 状态
mysql -uroot -p -e "SHOW ENGINE INNODB STATUS\G" > /opt/innodb_status.txt
# 批量检查所有表
for db in $(mysql -uroot -p -e "SHOW DATABASES;" | tail -n +2); do
for tbl in $(mysql -uroot -p -e "SHOW TABLES IN $db;" | tail -n +2); do
mysql -uroot -p -e "CHECK TABLE $db.$tbl FAST" >> /opt/table_check.log
done
done
# 磁盘使用告警
#!/bin/bash
USAGE=$(df /var/lib/mysql | awk 'NR==2{print $5}' | sed 's/%//')
if [ "$USAGE" -gt 80 ]; then
echo "MySQL disk usage at ${USAGE}%." | mail -s "Disk Usage Alert" dba@example.com
fi