在 1 核 2G(1 CPU, 2GB RAM)的服务器上运行 MySQL,资源非常紧张,核心原则是“做减法”和“精准配置”:避免过度分配内存导致 OOM(内存溢出),同时减少不必要的后台开销。以下是关键优化建议:
🔧 一、MySQL 配置文件(my.cnf / mysqld.cnf)核心调优
[mysqld]
# 基础设置
basedir = /usr/local/mysql
datadir = /var/lib/mysql
socket = /tmp/mysql.sock
port = 3306
skip-name-resolve # 禁用 DNS 反向解析,提升连接速度
# 内存关键参数(总内存 2G,建议留给系统 + 应用至少 500MB)
max_connections = 50 # 限制并发,避免线程爆炸
thread_cache_size = 8 # 缓存线程,减少创建开销
table_open_cache = 400 # 表句柄缓存(默认 400 已较合理)
open_files_limit = 1024 # 文件描述符上限(需与 max_connections 匹配)
# InnoDB 缓冲池(重中之重!占可用内存的 50%~70%)
innodb_buffer_pool_size = 1G # 推荐值:1024M(留 1G 给 OS 和其他进程)
innodb_log_file_size = 256M # 日志大小,平衡性能与崩溃恢复时间
innodb_flush_log_at_trx_commit = 2 # 权衡:0=最快但风险高;1=安全;2=折中(推荐生产用 2)
innodb_flush_method = O_DIRECT # 绕过 OS 缓存,避免双重缓存浪费内存
# 其他关键项
query_cache_type = 0 # MySQL 5.7+ 不推荐使用 query cache(有锁竞争)
sort_buffer_size = 256K # 每个连接单独分配,小值防内存耗尽
read_buffer_size = 256K
join_buffer_size = 256K
key_buffer_size = 32M # MyISAM 索引缓存(若只用 InnoDB 可设为 0)
# 日志与监控
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 # 记录超过 2 秒的慢查询
log_error = /var/log/mysql/error.log
✅ 注意:
innodb_buffer_pool_size不要超过物理内存的 70%,否则可能触发 OOM Killer。- 所有
_buffer_size参数都是每连接独占,务必控制数量级(如sort_buffer_size设太小会导致排序失败,太大则多连接时迅速吃光内存)。
🛡️ 二、操作系统层优化
1. 启用 Swap(谨慎使用)
# 创建 1G swap(作为兜底,非主力)
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
⚠️ 但需降低 vm.swappiness 避免频繁交换:
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
2. 调整文件系统挂载选项
对数据盘(如 /var/lib/mysql)添加 noatime 减少写入:
# /etc/fstab 示例
/dev/sda1 /var/lib/mysql ext4 defaults,noatime,nodiratime 0 2
3. 关闭不必要服务 & 防火墙规则精简
- 停用
firewalld/ufw仅开放 3306(或改用 iptables 精确规则) - 关闭
rsyslog高频日志(或过滤 MySQL 日志到独立文件)
📊 三、数据库设计 & 查询层面优化
| 优化项 | 说明 |
|---|---|
| 只使用 InnoDB | 放弃 MyISAM(无事务、行锁差),统一引擎为 InnoDB |
| 合理建索引 | 避免全表扫描;复合索引遵循最左前缀;覆盖索引减少回表 |
| **避免 SELECT *** | 只查必要字段,减少网络传输与内存占用 |
| 分页优化 | 大表分页用 WHERE id > last_id LIMIT N 替代 OFFSET |
| 批量操作 | 用 INSERT INTO ... VALUES (...), (...) 代替单条插入 |
| 定期 ANALYZE TABLE | 保持统计信息准确,避免执行计划偏差 |
🔍 工具辅助:
-- 查看当前内存压力
SHOW STATUS LIKE 'Innodb_buffer_pool_pages%';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE '%buffer%';
-- 开启慢查询分析
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
⚠️ 四、必须规避的陷阱
| 风险点 | 后果 | 解决方案 |
|---|---|---|
innodb_buffer_pool_size > 1.5G |
OOM Kill | 严格控制在 1G 以内 |
max_connections = 200+ |
线程上下文切换风暴 | 限制在 50~80,配合应用层连接池 |
| 未禁用 DNS 解析 | 登录延迟 1~5 秒 | skip-name-resolve |
| 大量临时表落盘 | I/O 瓶颈 | 确保 tmpdir 在 SSD 或内存盘(/dev/shm) |
| 自动备份脚本无限增长 binlog | 磁盘爆满 | 设置 expire_logs_days = 7 + 定时清理 |
🔄 五、监控与告警(轻量级)
# 安装 mysqltuner.pl(在线脚本)
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl
chmod +x mysqltuner.pl
./mysqltuner.pl
# 或使用 percona-monitoring-plugins(轻量版)
# 或简单 shell 脚本监控:
watch -n 5 'free -h && echo "---" && mysqladmin status'
✅ 总结:1 核 2G 生存法则
“小内存 → 小缓冲池 + 低并发 + 精索引 + 勤监控”
优先保障核心业务稳定,而非追求高性能。必要时考虑:
- 应用层读写分离(主从架构需更多资源)
- 迁移至云厂商的 RDS(按量付费,弹性扩容)
- 使用 Redis 缓存热点数据,减轻 DB 压力
如需具体场景(如 WordPress、小型 ERP)的定制配置,可提供更多信息进一步细化方案。
CLOUD云枢