在 2GB内存的服务器上同时运行 MySQL 和 Redis 是一个极具挑战性的场景,因为两者都是内存密集型服务。如果配置不当,极易触发 Linux OOM(Out of Memory) killer导致服务崩溃。
以下是合理分配内存、避免 OOM 的系统化方案:
🔑 核心原则
- 预留系统内存:Linux 内核、文件系统缓存、进程开销等至少预留 512MB~768MB。
- MySQL 与 Redis 共享可用内存约 1.2GB~1.4GB。
- 设置内存上限:为 MySQL 和 Redis 显式限制最大内存使用量。
- 启用交换空间(Swap)作为最后防线(但性能较差,仅用于防崩溃)。
- 监控 + 自动重启机制:防止静默失败。
📊 推荐内存分配比例
| 组件 | 推荐最大内存 | 说明 |
|---|---|---|
| 系统预留 | 512MB ~ 768MB | OS + buffer cache + 其他进程 |
| Redis | 256MB ~ 512MB | 适合小数据集,开启 LRU/LFU 淘汰策略 |
| MySQL | 512MB ~ 768MB | 重点控制 InnoDB Buffer Pool 大小 |
| Swap | 1GB ~ 2GB | 作为安全垫,避免 OOM Killer 直接杀进程 |
✅ 典型配置示例:
- 系统预留:600MB
- Redis maxmemory: 512MB
- MySQL innodb_buffer_pool_size: 512MB
- Swap: 1GB
⚙️ 具体配置步骤
1. MySQL 配置优化(my.cnf 或 mysqld.cnf)
[mysqld]
# 限制 InnoDB 缓冲池大小(最关键!)
innodb_buffer_pool_size = 512M
# 减少其他内存消耗
innodb_log_file_size = 128M # 默认值,可适当减小
innodb_flush_method = O_DIRECT # 避免双重缓存
table_open_cache = 200 # 默认可能过高,调低
thread_cache_size = 8 # 根据并发调整
max_connections = 50 # 限制最大连接数,避免线程栈内存爆炸
# 禁用不需要的功能
skip-name-resolve # 加快连接速度
performance_schema = OFF # 关闭性能模式节省内存
💡 注意:
innodb_buffer_pool_size应占 MySQL 总内存的 70%~80%,其余留给 log、sort buffer、join buffer 等。
2. Redis 配置优化(redis.conf)
# 设置最大内存上限
maxmemory 512mb
# 设置淘汰策略(关键!)
maxmemory-policy allkeys-lru # 或 volatile-lru / allkeys-lfu
# 持久化方式选择(牺牲持久性换内存)
save "" # 关闭 RDB 快照
appendonly no # 关闭 AOF(或设为 no-appendfsync-on-rewrite yes)
# 压缩对象以节省内存
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
# 禁用不必要的模块
loadmodule /path/to/module.so # 不要加载非必要模块
💡 Redis 内存模型提示:
- Redis 使用 SDS 字符串,小键值对开销大。
- 使用
redis-cli --bigkeys定期清理大 key。- 考虑使用 Redis Modules(如 ReJSON、RedisGraph)是否必要?非必要则禁用。
3. 创建 Swap 空间(安全垫)
# 检查当前 swap
free -h
# 创建 1GB 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
# 调整 swappiness(建议 10~30,避免过度使用 swap)
sudo sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
⚠️ 警告:Swap 会严重降低性能,仅用于防止 OOM 杀死进程。生产环境应优先扩容内存而非依赖 Swap。
4. 监控与告警
使用工具监控内存使用:
# 实时查看内存
top -m memory
# 监控 MySQL 内存
mysqladmin extended-status -i1 | grep -E "Innodb_buffer_pool_pages_data|Threads_running"
# 监控 Redis 内存
redis-cli info memory | grep used_memory_human
# 监控 OOM 事件
dmesg | grep -i oom
journalctl -k | grep -i oom
推荐监控方案:
- Prometheus + Grafana:部署 node_exporter 监控系统内存,mysql_exporter 和 redis_exporter 分别监控数据库。
- 简单脚本告警:当内存使用 >85% 时发送通知。
5. 应用层优化(减少内存压力)
MySQL 侧:
- 避免大查询(
SELECT *→ 只查必要字段) - 添加合适索引,减少临时表使用
- 分库分表,缩小单库数据量
- 定期
OPTIMIZE TABLE清理碎片
Redis 侧:
- 使用哈希结构代替多个独立 key
- 设置过期时间(TTL),避免脏数据堆积
- 定期删除无用 key
- 使用
SCAN替代KEYS *(避免阻塞)
🧪 测试验证
-
压测模拟高负载:
# MySQL 压测 mysqlslap --concurrency=50 --iterations=100 --create-schema=testdb --query="SELECT * FROM users WHERE id=?;" --number-of-queries=10000 # Redis 压测 redis-benchmark -n 100000 -c 50 -d 100 -
观察内存曲线:
- 确保 MySQL 和 Redis 内存使用稳定在设定上限以下。
- 无频繁 Swap 使用。
- 无 OOM 日志。
-
故障注入测试:
- 手动增加数据量,观察淘汰策略是否生效。
- 模拟突发流量,观察系统是否稳定。
🚨 极端情况应对
| 问题 | 解决方案 |
|---|---|
| 内存持续不足 | 升级服务器至 4GB+ 内存 |
| Redis 频繁淘汰数据 | 检查是否有关键数据被误淘汰;改用 volatile-lru 保留有 TTL 的数据 |
| MySQL 慢查询多 | 优化 SQL 和索引;考虑读写分离 |
| Swap 使用率高 | 立即扩容内存;检查是否有内存泄漏 |
| OOM 发生 | 检查 dmesg 日志;临时重启服务;长期需扩容 |
✅ 总结 checklist
- [ ] 系统预留 ≥512MB
- [ ] Redis
maxmemory设置为 256~512MB,启用 LRU/LFU 淘汰 - [ ] MySQL
innodb_buffer_pool_size设置为 512~768MB - [ ] 创建 1GB Swap 作为安全垫
- [ ] 设置
vm.swappiness=10 - [ ] 安装 Prometheus + Grafana 监控
- [ ] 定期清理 Redis 大 key 和 MySQL 碎片
- [ ] 限制 MySQL
max_connections和 Redis 客户端连接数 - [ ] 编写自动化脚本监控内存并告警
💡 最终建议:2GB 内存跑 MySQL + Redis 属于极限配置。如果业务增长,最可靠的方案是升级到 4GB 或更高内存的服务器。内存成本远低于因 OOM 导致的服务中断和数据丢失风险。
云知识CLOUD