速卖通素材
奋斗

2GB内存下MySQL和Redis如何合理分配内存避免OOM?

服务器

在2GB内存的机器上同时运行 MySQL 和 Redis 是一个典型的资源受限场景。如果配置不当,极易触发 OOM(Out of Memory),导致服务崩溃。

以下是经过验证的合理分配策略、关键参数配置及监控建议


🎯 核心原则

  1. Redis 是“内存大户”:Redis 默认使用 maxmemory 限制,但需预留操作系统缓存空间。
  2. MySQL 依赖文件系统缓存:InnoDB Buffer Pool 不应占满物理内存,否则 OS 无空间做页缓存(Page Cache),反而降低 I/O 性能。
  3. 预留系统开销:至少保留 200~300MB 给操作系统内核、进程栈、Swap(如有)等。

✅ 推荐内存分配方案(总内存 2GB = 2048MB)

组件 推荐最大内存 说明
Redis 512 MB ~ 768 MB 设置 maxmemory,启用淘汰策略
MySQL (InnoDB) 512 MB ~ 768 MB innodb_buffer_pool_size
其他开销 ~500 MB OS + Swap + MySQL/Redis 进程开销 + 临时表 + 日志缓冲

💡 更保守的起步配置(适合小项目)

  • Redis: 400 MB
  • MySQL: 400 MB
  • 剩余: ~1200 MB 用于 OS 和突发负载

🔧 关键参数配置

1. Redis 配置(redis.conf

# 1. 设置最大内存上限(必须!)
maxmemory 512mb

# 2. 当内存达到上限时的淘汰策略(根据业务选择)
# 常用:LRU 最近最少使用,或 TTL 过期键优先
maxmemory-policy allkeys-lru

# 3. 禁用 Swap(Redis 对延迟敏感,Swap 会导致卡顿)
vm-swap-file /dev/null  # Redis 4+ 已移除 vm 相关命令,确保系统层面不启用 swap 或设为最低优先级

# 4. 开启内存碎片整理(可选,定期执行)
# redis-cli MEMORY PURGE

⚠️ 注意:Redis 实际占用内存会略高于 maxmemory(因元数据、线程栈等),因此建议将 maxmemory 设置为可用内存的 70%~80%

2. MySQL 配置(my.cnf / mysqld.cnf

[mysqld]

# 1. InnoDB 缓冲池大小(最关键)
# 公式:innodb_buffer_pool_size ≈ 总内存 × 25%~30%
innodb_buffer_pool_size = 512M

# 2. 单实例可设为一个大的 buffer pool(提升性能)
innodb_buffer_pool_instances = 1

# 3. 连接数控制(避免每个连接占用过多内存)
max_connections = 50       # 根据应用并发调整,2GB 机器不宜过高
thread_cache_size = 8

# 4. 临时表内存限制
tmp_table_size = 16M
max_heap_table_size = 16M

# 5. 排序缓冲区(每个连接独立,需谨慎)
sort_buffer_size = 256K
join_buffer_size = 256K
read_buffer_size = 128K
read_rnd_buffer_size = 128K

# 6. 查询缓存(MySQL 5.7 及以下才有效,8.0 已移除)
# query_cache_type = 1
# query_cache_size = 32M   # 高并发下可能成为瓶颈,建议关闭或设小

📌 为什么 MySQL Buffer Pool 不能太大?

  • 如果 innodb_buffer_pool_size 接近物理内存,OS 无法为文件 I/O 分配足够的 Page Cache。
  • MySQL 本身还会用其他内存(如 sort/join buffer、线程栈、日志缓冲等)。
  • 最佳实践:Buffer Pool 占总内存 25%~30%,其余留给 OS 和其他 MySQL 组件。

🛡️ 防止 OOM 的系统级措施

1. 启用 Swap(谨慎使用)

虽然 Redis 不喜欢 Swap,但在 2GB 小内存下,完全禁用 Swap 可能导致内核直接 kill 进程。

# 创建 1GB swap 文件
dd if=/dev/zero of=/swapfile bs=1M count=1024
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# 设置低 swappiness,避免频繁换页
echo 'vm.swappiness=10' >> /etc/sysctl.conf
sysctl -p

2. 使用 cgroups 或 systemd 限制内存(高级)

通过 systemd 限制每个服务的最大内存,防止单个服务拖垮系统:

# /etc/systemd/system/redis.service.d/override.conf
[Service]
MemoryMax=600M
MemoryHigh=500M

[Service]
MemoryMax=600M
MemoryHigh=500M

3. 监控与告警

  • 使用 htopfree -m 实时观察内存。
  • 配置 Prometheus + Node Exporter + Grafana 监控:
    • node_memory_MemAvailable_bytes
    • Redis used_memory vs maxmemory
    • MySQL Innodb_buffer_pool_pages_free

🔄 运维建议

  1. 分阶段扩容

    • 初期:Redis 400M + MySQL 400M
    • 观察高峰后,逐步调高至 512M/512M
    • 若仍不足,优先考虑优化 SQL 和索引,而非盲目加内存。
  2. Redis 持久化策略

    • 使用 RDB 而非 AOF,减少内存压力。
    • 或采用 AOF everysec + auto-aof-rewrite-percentage 100,避免重写时内存X_X倍。
  3. MySQL 优化

    • 确保所有查询都有索引,避免全表扫描消耗大量临时表内存。
    • 避免大事务和复杂 JOIN。
  4. 重启策略

    • 配置自动重启脚本,当检测到 OOM 时快速恢复。

✅ 总结检查清单

检查项 状态
Redis maxmemory 已设置
Redis maxmemory-policy 已配置
MySQL innodb_buffer_pool_size ≤ 768M
MySQL max_connections 适中(≤50)
系统保留 ≥300MB 给 OS
Swap 已启用且 swappiness 较低
已部署内存监控告警

按照以上配置,你可以在 2GB 内存下稳定运行 MySQL + Redis,并大幅降低 OOM 风险。

未经允许不得转载:轻量云Cloud » 2GB内存下MySQL和Redis如何合理分配内存避免OOM?