Linux 5.15 内存交换(Swap)实战:4GB 物理内存下 MySQL 8.0 性能调优与 OOM 规避
在资源受限的服务器环境中,如何让内存密集型应用如 MySQL 稳定运行是一门艺术。当物理内存仅有 4GB 时,合理配置 Swap 空间和优化内存参数不仅能避免 OOM(Out of Memory)杀手误伤关键进程,还能在性能与可靠性之间找到最佳平衡点。本文将手把手带您完成从 Swap 配置到 MySQL 调优的全流程实战。
1. Swap 基础与 Linux 5.15 内核特性
现代 Linux 系统中,Swap 不再只是简单的"内存溢出区",而是内存管理策略的重要组成部分。Linux 5.15 内核引入了以下关键改进:
- 主动式 Swap 预读:当系统检测到内存压力时,会提前将不活跃页面移至 Swap
- cgroup v2 内存控制:更精细的 per-cgroup Swap 限制策略
- zswap 压缩缓存:对即将换出的页面进行压缩存储(需启用
CONFIG_ZSWAP)
Swap 的三种实现方式对比:
| 类型 | 性能 | 灵活性 | 适用场景 |
|---|---|---|---|
| 独立 Swap 分区 | 高 | 低 | 长期稳定的生产环境 |
| Swap 文件 | 中 | 高 | 云主机等动态环境 |
| zswap | 可变 | 中 | 内存较小但有快速存储设备 |
提示:在云环境中,由于无法轻易调整分区,Swap 文件通常是更实用的选择
2. 配置 Swap 的最佳实践
2.1 创建 Swap 文件(以 Ubuntu 22.04 为例)
# 创建 4GB 的 Swap 文件(大小建议为物理内存的 1-2 倍) sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 永久生效 echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab关键参数验证:
sudo swapon --show free -h2.2 优化 swappiness 参数
swappiness 值(0-100)控制内核使用 Swap 的倾向性:
# 查看当前值 cat /proc/sys/vm/swappiness # 临时设置为更保守的值(推荐 10-30 对于数据库服务器) sudo sysctl vm.swappiness=20 # 永久生效 echo 'vm.swappiness=20' | sudo tee -a /etc/sysctl.conf对于 MySQL 专用服务器,可以设置更激进的内存保留策略:
echo 'vm.min_free_kbytes=65536' | sudo tee -a /etc/sysctl.conf3. MySQL 8.0 内存调优策略
3.1 关键内存参数计算
在 4GB 物理内存的服务器上,建议分配:
# /etc/mysql/my.cnf [mysqld] innodb_buffer_pool_size = 2G # 物理内存的 50% innodb_log_file_size = 256M # 每个日志文件大小 innodb_log_files_in_group = 2 # 日志文件数量 key_buffer_size = 128M # MyISAM 索引缓存(如使用) query_cache_size = 0 # 建议禁用查询缓存 tmp_table_size = 64M max_heap_table_size = 64M table_open_cache = 2000内存分配检查工具:
# 查看 MySQL 实际内存使用 sudo pmap -x $(pgrep mysqld) | grep total3.2 预防 OOM 的特殊配置
[mysqld] oom-score = -800 # 降低被 OOM killer 选中的概率 performance_schema = ON # 开启性能监控 # 限制连接内存使用 max_connections = 50 thread_stack = 256K4. 监控与性能分析
4.1 Swap 活动监控
# 实时监控 Swap I/O vmstat 1 # 查看 si/so 列 sar -W 1 # 查看页面交换统计 # 更详细的 Swap 使用分析 cat /proc/meminfo | grep -i swap4.2 MySQL 内存压力测试
使用 sysbench 模拟负载:
sysbench oltp_read_write \ --db-driver=mysql \ --mysql-user=root \ --mysql-password=yourpassword \ --mysql-db=sbtest \ --tables=10 \ --table-size=100000 \ --threads=8 \ --time=300 \ prepare sysbench oltp_read_write \ --db-driver=mysql \ --mysql-user=root \ --mysql-password=yourpassword \ --mysql-db=sbtest \ --tables=10 \ --table-size=100000 \ --threads=8 \ --time=300 \ run4.3 性能数据对比
Swap 开启前后的 TPS 对比示例:
| 场景 | 平均 TPS | 95% 延迟(ms) | OOM 发生次数 |
|---|---|---|---|
| 无 Swap | 1124 | 45 | 3/5 次测试 |
| 4GB Swap 文件 | 986 | 68 | 0/5 次测试 |
| zswap 启用 | 1057 | 52 | 0/5 次测试 |
5. 高级调优技巧
5.1 使用 cgroup v2 限制 MySQL 内存
# 创建 cgroup sudo mkdir /sys/fs/cgroup/mysql echo "+memory" | sudo tee /sys/fs/cgroup/cgroup.subtree_control echo "3G" | sudo tee /sys/fs/cgroup/mysql/memory.high # 将 MySQL 进程加入 cgroup echo $(pgrep mysqld) | sudo tee /sys/fs/cgroup/mysql/cgroup.procs5.2 内核参数终极优化
# 减少内存碎片化 echo 'vm.vfs_cache_pressure=50' | sudo tee -a /etc/sysctl.conf echo 'vm.dirty_ratio=10' | sudo tee -a /etc/sysctl.conf echo 'vm.dirty_background_ratio=5' | sudo tee -a /etc/sysctl.conf # 应用所有修改 sudo sysctl -p6. 故障排查与应急方案
当系统出现内存压力时,按以下步骤排查:
快速诊断:
free -h top -o %MEM dmesg | grep oomMySQL 专用检查:
SHOW ENGINE INNODB STATUS\G SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_wait%';紧急处理:
# 临时扩大 Swap sudo dd if=/dev/zero of=/swapfile2 bs=1M count=2048 sudo mkswap /swapfile2 sudo swapon /swapfile2 # 杀死最耗内存的进程 sudo kill -9 $(ps -eo pid,%mem --sort=-%mem | head -n 2 | tail -n 1 | awk '{print $1}')
在实际生产环境中,我们曾遇到一个典型案例:某电商平台的促销活动期间,4GB 内存的数据库服务器通过合理配置 Swap 和 MySQL 参数,成功扛住了平时 3 倍的流量冲击,而之前同样配置的服务器因为没有优化 Swap 设置,在流量高峰时频繁触发 OOM 导致服务不可用。