在 2 核 2G 的 Linux 服务器上运行 MySQL,资源非常紧张,必须通过精细配置避免 OOM(内存溢出)和频繁 Swap。以下是针对该环境的优化建议:
一、核心原则
- 保守分配内存:MySQL 默认会占用大量内存(如
innodb_buffer_pool_size),需手动限制。 - 减少并发压力:降低
max_connections,避免连接数爆炸导致内存耗尽。 - 禁用不必要功能:关闭不用的存储引擎、日志等。
- 优先使用 InnoDB:MyISAM 已不再推荐,且对内存控制更差。
二、关键参数配置(my.cnf / my.ini)
[mysqld]
# 基础设置
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
pid-file=/var/run/mysqld/mysqld.pid
# 字符集(统一为 utf8mb4)
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 内存管理(核心!)
# 总可用内存约 1.8G(预留 200M 给 OS 和其他进程)
innodb_buffer_pool_size = 512M # 占物理内存 25%~30%,最安全值
innodb_log_file_size = 64M # 日志大小,不宜过大
innodb_flush_method = O_DIRECT # 绕过 OS 缓存,减少双重缓冲
# 连接与线程
max_connections = 50 # 默认 151 太高,根据实际业务调整
thread_cache_size = 10 # 减少线程创建开销
table_open_cache = 200 # 表打开数量,小环境无需太大
# 查询缓存(MySQL 8.0+ 已移除;若用 5.7 可考虑关闭)
query_cache_type = 0 # 或 query_cache_size=0(推荐关闭,因锁竞争严重)
query_cache_limit = 0
# 日志与性能
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 # 超过 2 秒的记录为慢查询
log_queries_not_using_indexes = 1 # 记录未走索引的查询(可选)
# 其他优化
skip-name-resolve # 禁用 DNS 反向解析,提速连接
tmp_table_size = 32M
max_heap_table_size = 32M # 临时表最大内存,避免落盘
# 关闭不需要的特性
default-storage-engine = innodb
skip-symbolic-links # 禁用符号链接(安全加固)
✅ 注意:
innodb_buffer_pool_size是最关键参数。在 2G 机器上,建议设为 512M ~ 768M,切勿超过 800M。- 若使用 Docker 或容器化部署,需确保容器内存限制 ≥ 1.5G,否则 MySQL 可能被系统杀死。
三、操作系统层面优化
1. 关闭 Swap(推荐)
# 临时关闭
sudo swapoff -a
# 永久关闭:编辑 /etc/fstab,注释掉 swap 分区/文件行
# 然后重启生效
⚠️ 原因:Swap 会导致磁盘 I/O 激增,严重拖慢数据库响应。宁可让 MySQL 崩溃(OOM Killer 终止),也不愿进入 Swap。
2. 调整内核参数
# 增加 TCP 连接队列
echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf
echo "net.ipv4.tcp_max_syn_backlog = 2048" >> /etc/sysctl.conf
# 禁用 NUMA(单核双核机器通常无影响,但可避免潜在问题)
echo "numa_balancing = 0" >> /etc/sysctl.conf
sysctl -p
3. 文件系统优化
- 使用
ext4或xfs文件系统(避免 ext3)。 - 挂载选项添加
noatime(减少写入元数据):# /etc/fstab 示例 /dev/sda1 /var/lib/mysql ext4 defaults,noatime,nodiratime 0 2
四、应用层与架构建议
- 启用连接池:应用端使用 HikariCP、Druid 等连接池,复用连接,减少
max_connections压力。 - 读写分离:如有条件,将读请求分流到只读副本(即使只是单机主从复制)。
- 定期清理日志:
-- 查看并清理二进制日志(保留最近 7 天) PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY); - 监控告警:
- 使用
mysqltuner.pl分析当前配置:wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl chmod +x mysqltuner.pl ./mysqltuner.pl - 监控指标:
Innodb_buffer_pool_read_requests,Threads_connected,Uptime,Swap usage。
- 使用
五、常见陷阱规避
| 问题 | 解决方案 |
|---|---|
| MySQL 被 OOM Killer 杀死 | 检查 /var/log/messages 或 dmesg,确认是否因内存不足;调低 innodb_buffer_pool_size |
| 查询缓慢 | 使用 EXPLAIN 分析执行计划,添加缺失索引;避免 SELECT * |
| 连接超时 | 提高 wait_timeout 和 interactive_timeout(如 28800 秒) |
| 临时表落盘 | 增大 tmp_table_size 和 max_heap_table_size |
六、替代方案(如果仍不够用)
- 升级到更高配置服务器:最低建议 4G 内存。
- 迁移到轻量级数据库:如 SQLite(适合极低并发)、Redis(缓存热点数据)。
- 使用云数据库服务:如阿里云 RDS、AWS RDS,自动优化底层资源。
✅ 总结:在 2C2G 环境下,内存控制 > 并发控制 > 日志优化 > 索引优化。优先保证 MySQL 不崩溃,再追求性能提升。每次修改配置后务必重启 MySQL 并观察运行状态。
云服务器