在2GB内存的服务器上部署MySQL确实容易遇到OOM问题。以下是一套完整的调优方案:
1. 核心参数优化(my.cnf/my.ini)
[mysqld]
# 基础设置
innodb_buffer_pool_size = 256M # 关键!不要超过总内存的50%
key_buffer_size = 32M
max_connections = 50 # 减少并发连接数
thread_cache_size = 8
table_open_cache = 256
# InnoDB优化
innodb_log_file_size = 64M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 2 # 平衡性能和数据安全
innodb_file_per_table = ON
innodb_flush_method = O_DIRECT
# 查询缓存(MySQL 8.0已移除,5.7可谨慎使用)
# query_cache_type = 0 # 建议关闭,避免内存竞争
# 临时表
tmp_table_size = 32M
max_heap_table_size = 32M
# 连接和线程
thread_stack = 256K
sort_buffer_size = 2M
read_buffer_size = 1M
read_rnd_buffer_size = 1M
join_buffer_size = 1M
2. 操作系统级优化
调整SWAP空间(确保有备用交换空间)
# 检查当前swap
free -h
# 创建swap文件(如果不足)
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 永久生效
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
调整内核参数
# 编辑 /etc/sysctl.conf
vm.swappiness = 10 # 降低swap使用倾向
vm.overcommit_memory = 0 # 保守的内存分配策略
vm.overcommit_ratio = 50
# 生效配置
sysctl -p
3. MySQL监控与诊断
查看内存使用情况
-- 查看当前内存分配
SHOW VARIABLES LIKE '%buffer%';
SHOW VARIABLES LIKE '%cache%';
-- 查看内存使用统计
SELECT * FROM sys.memory_global_total;
SELECT * FROM sys.memory_by_thread_by_current_bytes LIMIT 10;
识别内存消耗大的连接
-- 查看连接内存使用(MySQL 5.7+)
SELECT
thread_id,
user,
current_allocated
FROM sys.memory_by_thread_by_current_bytes
ORDER BY current_allocated DESC
LIMIT 10;
4. 应用层优化建议
连接池配置
# 在应用连接池中设置
maxActive=20 # 最大连接数
maxIdle=10 # 最大空闲连接
minIdle=5 # 最小空闲连接
testOnBorrow=true # 验证连接有效性
定期维护
# 设置定时任务清理
# 每天凌晨优化表
0 3 * * * mysqlcheck -o --all-databases
# 定期分析慢查询日志
pt-query-digest /var/log/mysql/mysql-slow.log
5. 应急措施
当出现OOM时:
-
立即重启MySQL并调整参数
sudo systemctl restart mysql -
使用内存限制工具
# 使用systemd限制内存 # 编辑 /etc/systemd/system/mysql.service.d/limits.conf [Service] MemoryLimit=1.5G -
考虑轻量级替代方案
- MariaDB(更轻量)
- PostgreSQL(内存管理更好)
- SQLite(适合小型应用)
6. 监控告警设置
# 安装监控工具
# CentOS
sudo yum install -y htop atop
# Ubuntu
sudo apt install -y htop atop
# 设置监控脚本
cat > /usr/local/bin/check_mysql_mem.sh << 'EOF'
#!/bin/bash
MEM_USED=$(free -m | awk '/Mem:/ {print $3}')
MEM_TOTAL=$(free -m | awk '/Mem:/ {print $2}')
MEM_PERCENT=$((MEM_USED*100/MEM_TOTAL))
if [ $MEM_PERCENT -gt 85 ]; then
echo "警告:内存使用率 ${MEM_PERCENT}%"
# 发送告警邮件或通知
fi
EOF
chmod +x /usr/local/bin/check_mysql_mem.sh
7. 长期解决方案建议
- 升级硬件:至少升级到4GB内存
- 使用云数据库:如AWS RDS、阿里云RDS等托管服务
- 分库分表:减少单实例压力
- 读写分离:主库写,从库读
- 使用缓存层:如Redis缓存热点数据
关键原则:
- innodb_buffer_pool_size 不要超过总内存的50%
- 监控 实际内存使用,而非仅看配置值
- 定期分析 慢查询,优化SQL语句
- 考虑 数据归档,删除不必要的历史数据
根据你的具体使用场景(OLTP还是OLAP),可能需要进一步调整。建议先在测试环境验证配置,再应用到生产环境。
CLOUD技术笔记