在 2 核 4G 的服务器上运行 MySQL,遇到卡顿是非常常见的问题。这通常是因为 MySQL 默认配置是为高配服务器设计的,导致内存分配过大或磁盘 I/O 成为瓶颈。
要解决这个问题,核心思路是“限制资源占用”和“优化查询效率”。以下是分步骤的优化方案:
1. 修改 my.cnf 配置文件(最关键)
MySQL 默认的缓冲池(InnoDB Buffer Pool)通常会占用大量内存,导致系统内存不足,进而触发 Swap(交换分区),这是卡顿的主要原因。
请编辑 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf,找到 [mysqld] 部分,进行如下调整:
[mysqld]
# 1. 限制最大连接数 (防止连接风暴消耗 CPU)
max_connections = 50
# 2. 调整 InnoDB 缓冲池大小 (核心优化点)
# 对于 4G 内存,建议设置为物理内存的 50%-60% (约 2G-2.5G)
# 避免给 OS 和其他进程留出足够空间
innodb_buffer_pool_size = 2G
# 3. 关闭不必要的日志功能 (如果不需要详细审计)
# log_bin 如果不需要主从复制可以暂时关闭,或者调整 binlog 格式为 ROW
# 但生产环境通常建议保留,仅做微调
# sync_binlog = 1
# innodb_flush_log_at_trx_commit = 1
# 4. 调整临时表大小 (防止临时表落盘导致 IO 卡顿)
tmp_table_size = 64M
max_heap_table_size = 64M
# 5. 开启慢查询日志 (用于后续分析卡顿原因)
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 # 超过 2 秒的查询记录
# 6. 其他优化
# 减少排序缓冲区,防止内存溢出
sort_buffer_size = 256K
read_buffer_size = 256K
read_rnd_buffer_size = 256K
注意:修改后必须重启 MySQL 服务 (systemctl restart mysqld) 才能生效。
2. 检查并禁用 Swap(交换分区)
Linux 系统在内存不足时会将数据写入硬盘(Swap),而硬盘读写速度远低于内存,一旦频繁使用 Swap,服务器会瞬间卡死。
-
查看是否开启了 Swap:
free -h如果
Swap列有数值且在使用中,说明内存已爆满。 -
临时关闭 Swap(测试用):
swapoff -a警告:如果此时内存真的不够,数据库可能会直接崩溃(OOM Killer)。建议在确认上述
my.cnf配置已调低内存占用后再操作。 -
永久禁止 Swap(推荐):
注释掉/etc/fstab中的 swap 行,然后执行swapoff -a。让系统宁愿报错 OOM 也不要用慢速硬盘,这样比卡死更容易排查问题。
3. 优化 SQL 查询与索引
如果配置没问题,卡顿往往源于“烂 SQL"。
- 开启慢查询日志:
利用上面配置的slow_query_log,等待一段时间,查看/var/log/mysql/slow.log。 - 使用
EXPLAIN分析:
对慢查询执行EXPLAIN SELECT ...,检查:type是否为ALL(全表扫描)?如果是,需要加索引。key字段是否有实际用到索引?rows扫描行数是否巨大?
- 添加缺失的索引:
在WHERE、ORDER BY、GROUP BY涉及的字段上建立索引。- 注意:不要过度索引,写操作(INSERT/UPDATE)会变慢。
4. 硬件层面的辅助手段
如果软件优化后依然吃力,可以考虑以下低成本方案:
- 更换 SSD 硬盘:
机械硬盘(HDD)的随机读写性能极差,MySQL 极度依赖随机 IO。如果是 HDD,换成 SSD 能带来质的飞跃。 - 增加内存:
如果预算允许,将内存升级到 8G 是最直接的解决方案。 - 使用轻量级缓存:
引入 Redis 作为缓存层,将热点数据放在 Redis 中,减少 MySQL 的直接查询压力。
5. 紧急排查命令
当服务器再次卡顿时,立即执行以下命令定位问题:
-
查看负载:
top关注
load average是否超过 CPU 核数(如 2 核超过 2.0),以及%wa(IO Wait)是否很高。如果%wa很高,说明是磁盘 IO 瓶颈;如果%si/%us很高,说明是 CPU 或锁竞争。 -
查看当前活跃线程:
SHOW PROCESSLIST;如果有大量状态为
Sending data,Sorting result,Locked的线程,说明是特定查询卡住了。 -
查看 InnoDB 状态:
SHOW ENGINE INNODB STATUSG查看是否有死锁(Deadlock)或大量的页冲突。
总结建议
对于 2 核 4G 的配置,最优先的操作是将 innodb_buffer_pool_size 严格限制在 2GB 左右,并确保没有开启 Swap。这通常能解决 80% 的内存导致的卡顿问题。如果依然卡顿,请务必通过慢查询日志找出那条“最慢的 SQL"并进行索引优化。
PHPWP博客