为什么香港服务器的MySQL服务频繁崩溃?如何找到并解决问题?

为什么香港服务器的MySQL服务频繁崩溃?如何找到并解决问题?

我管理着数十台部署于香港的数据中心的Linux服务器。最近,我们的几台主打跨境业务的服务器,频繁出现 MySQL 服务宕机的问题。几乎每天凌晨 2 点到 4 点之间,应用团队就会在群里“狂轰滥炸”:连接超时、服务无响应、订单处理失败。

起初我以为是内存不足、恶意攻击或MySQL配置错误,但排查后发现事情并不简单。本文将用实战方式带你走一遍我排查并彻底解决问题的全过程,涉及系统配置、MySQL日志分析、磁盘IO监控、硬件瓶颈等关键细节。希望你在面对类似问题时不再一头雾水。

一、初始环境与服务器配置

我们的问题服务器配置如下:

  • 服务器位置:香港沙田数据中心
  • 操作系统:CentOS 7.9 (Kernel 3.10.0-1160)
  • MySQL版本:5.7.44

硬件配置:

  • CPU:Intel Xeon E5-2690 v4 @ 2.60GHz(共14核28线程)
  • 内存:64GB DDR4 ECC
  • 硬盘:2 × 1TB SSD(RAID 1)
  • 网络带宽:1Gbps 专线

服务器部署了以下主要服务:

  • Nginx(反向代理)
  • PHP-FPM(Laravel应用后端)
  • MySQL(单机主库)

二、现象分析与初步排查

1. 问题现象

/var/lib/mysql 中频繁生成 .err 文件;

mysqld 在凌晨时段意外退出;

查看日志:Out of memory: Kill process xxxx (mysqld);

错误代码:Got signal 11 (Segmentation fault)。

2. 系统日志关键内容

dmesg | grep -i kill
[123456.789123] Out of memory: Kill process 1532 (mysqld) score 984 or sacrifice child

说明内核 OOM Killer 介入,直接干掉了 MySQL。我们首先锁定内存问题。

三、精准定位:内存、配置还是硬盘?

1. 分析 MySQL 内存使用

查看 MySQL 启动参数(位于 /etc/my.cnf):

innodb_buffer_pool_size = 48G
query_cache_size = 0
tmp_table_size = 512M
max_connections = 1000

问题出在 innodb_buffer_pool_size:设置了 48G,加上连接数一多,MySQL高峰期总共占用内存接近 60G,严重超出了实际可用空间(系统自身 + 其他进程也要内存)。

我们用如下 SQL 分析内存消耗:

SHOW ENGINE INNODB STATUS;
SHOW STATUS LIKE 'Max_used_connections';

结果:

  • Max_used_connections = 856
  • 单个连接平均消耗约 4~6MB,856 × 6MB ≈ 5GB
  • 加上 buffer_pool,MySQL 实际内存消耗已经超出64GB物理内存。

✅ 解决方法:

  • 将 innodb_buffer_pool_size 从 48G 降为 32G
  • 配置连接池控制:使用 ProxySQL 或 PHP-FPM 连接复用
  • 设置 max_connections = 300

四、隐藏杀手:IO 瓶颈与 SSD 性能退化

在优化内存后,崩溃频率降低了,但凌晨仍偶有 MySQL 停止响应现象。

1. 使用 iostat 监控磁盘IO

iostat -x 1 10

结果显示:

Device: %util await
sda 98.5 305.12 ms
  • %util 高达 98.5%
  • await 超过 300ms

SSD明显已经过载。我们怀疑是表的临时文件和 binlog 导致磁盘IO飙升。

2. 分析 binlog 和临时表写入量

SHOW VARIABLES LIKE 'log_bin';
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';

结果显示:

  • Binlog 每日写入量超过 30GB
  • 每小时创建 5000+ 个磁盘临时表
  • 这说明磁盘写入压力很大。

✅ 解决方法:

  • 增加 tmp_table_size 和 max_heap_table_size 至 256M,减缓磁盘临时表生成
  • 清理长时间未清理的 binlog:设置 expire_logs_days = 3
  • 升级硬盘:将原 RAID 1 升级为 RAID 10,换用企业级 Samsung PM983 NVMe SSD

五、进阶优化:线程池与慢查询管理

1. 启用 MySQL 原生线程池(企业版功能)

如果你使用的是 Percona Server 或 MySQL 企业版:

thread_handling = pool-of-threads

我们改用了 Percona Server 5.7,支持线程池,有效防止连接风暴导致系统资源耗尽。

2. 开启慢查询日志 + pt-query-digest 分析

slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1

每天用 Percona Toolkit 工具分析:

pt-query-digest /var/log/mysql/mysql-slow.log > slowreport.txt

找出最耗资源的 SQL,例如:

SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at DESC;

优化方式:

  • 添加合适索引:CREATE INDEX idx_status_created_at ON orders(status, created_at);
  • 使用分页时避免 OFFSET:改为使用 WHERE id < ? LIMIT 20

六、网络层问题:TCP连接泄漏

在分析过程中,我们还发现部分 MySQL 连接并未关闭,导致连接堆积。

1. 使用 netstat 分析连接状态

netstat -anp | grep 3306 | grep ESTABLISHED | wc -l

发现即使无请求时仍有大量 ESTABLISHED 连接。

✅ 解决方法:

在 PHP-FPM 层使用 PDO 持久连接连接池

调整 MySQL 配置:

wait_timeout = 120
interactive_timeout = 120

配合应用层连接池中间件如 ProxySQL,实现连接复用

七、稳定运行,源于系统级理解

经过这轮深入排查与优化,MySQL 服务已经连续运行 30 天无宕机,系统平均负载从原先的 6~8 降至 1.5 左右。我们的经验教训是:

问题往往不是单点,而是多个瓶颈叠加;

不要“拍脑袋”优化,要用数据说话;

学会阅读系统日志和使用性能工具是运维的核心竞争力。

未经允许不得转载:A5数据 » 为什么香港服务器的MySQL服务频繁崩溃?如何找到并解决问题?

相关文章

contact