奋斗
努力

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

云计算

在仅 2GB 总内存 的受限环境中(如小型 VPS、嵌入式服务器或开发测试机),同时运行 MySQL 和 Redis 确实极易触发 OOM(Out of Memory)——尤其当两者默认配置未调优时。关键原则是:严格限制各自最大内存用量,预留系统基础开销,并禁用非必要功能。以下是经过生产验证的合理分配与配置方案:


✅ 一、内存分配建议(总 2GB = 2048MB)

组件 分配内存 说明
操作系统 + 基础服务 300–400MB 内核、SSH、日志、cron 等必需开销(free -h 观察空闲内存)
MySQL 900–1100MB 主要用于 innodb_buffer_pool_size(核心缓存),其余参数极简
Redis 500–600MB 通过 maxmemory 严格限制,启用 LRU/LFU 驱逐策略
缓冲/安全余量 ≥100MB 防止瞬时峰值导致 OOM(如 MySQL 排序、Redis 大 key 操作)

推荐分配(保守稳妥)

  • MySQL:1024MB
  • Redis:512MB
  • 系统+余量:≈512MB(含 swap 缓冲)

✅ 二、MySQL 关键调优(my.cnf

[mysqld]
# ▶️ 核心内存控制(必须!)
innodb_buffer_pool_size = 1024M    # 占 MySQL 分配的 90%+,勿超 1024M
innodb_log_file_size = 64M          # 减小日志文件(默认 48M→64M 可接受,勿过大)
innodb_flush_method = O_DIRECT      # 避免双重缓存(Linux)

# ▶️ 降低连接与临时内存
max_connections = 32                # 默认151→大幅缩减
sort_buffer_size = 256K             # 每连接排序缓存(默认2M→压到256K)
read_buffer_size = 128K             # 同上
join_buffer_size = 128K             # 同上
tmp_table_size = 32M                # 内存临时表上限(超过转磁盘)
max_heap_table_size = 32M           # MEMORY 表上限

# ▶️ 禁用非必要功能(省内存+提速)
skip_log_bin                        # 关闭 binlog(若无需主从/恢复)
skip_performance_schema             # 关闭性能库(节省 100MB+)
skip_log_error                      # 或设 log_error=/dev/null(减少 I/O)
innodb_file_per_table = ON          # 必须开启,避免 ibdata1 膨胀

# ▶️ 其他安全项
wait_timeout = 60                   # 空闲连接 60s 断开
interactive_timeout = 60

🔍 验证命令

# 查看实际内存占用(启动后)
mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
# 检查当前连接数和临时表使用
mysql -e "SHOW STATUS LIKE 'Threads_connected'; SHOW STATUS LIKE 'Created_tmp_disk_tables';"

✅ 三、Redis 关键调优(redis.conf

# ▶️ 内存硬限制(必须!)
maxmemory 512mb                     # 严格上限
maxmemory-policy allkeys-lru        # 或 volatile-lru(推荐 allkeys-lru,简单有效)
# maxmemory-samples 5               # 默认值即可

# ▶️ 禁用持久化(除非必须)→ 节省内存和 I/O
save ""                             # 关闭 RDB 自动保存
appendonly no                       # 关闭 AOF(若需持久化,改用 AOF rewrite + fsync everysec)

# ▶️ 降低后台任务开销
lazyfree-lazy-eviction yes          # 驱逐时异步释放内存(防阻塞)
lazyfree-lazy-expire yes            # 过期键异步删除
lazyfree-lazy-server-del yes        # DEL 异步处理(Redis 4.0+)

# ▶️ 网络与连接
tcp-keepalive 300                   # 保持连接活跃
timeout 300                         # 空闲连接超时
maxclients 100                      # 限制客户端数(默认 10000→大幅缩减)

# ▶️ 其他
hash-max-ziplist-entries 128        # 小哈希用压缩列表(省内存)
list-max-ziplist-size -2            # 小列表用压缩列表
set-max-intset-entries 512          # 小整数集合用 intset

🔍 验证命令

redis-cli info memory | grep -E "(used_memory_human|maxmemory_human|mem_fragmentation_ratio)"
# 应看到:used_memory_human ≤ 512MB,mem_fragmentation_ratio < 1.5

✅ 四、系统级防护(防止 OOM Kill)

  1. 启用并合理配置 swap(救命稻草)

    # 创建 512MB swap(不推荐 SSD 频繁写,但 2GB 内存下必要)
    sudo fallocate -l 512M /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
    # 调低 swappiness(减少主动 swap)
    echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
    sudo sysctl -p
  2. 配置 OOM Score(让 MySQL/Redis 不优先被 kill)

    # 查看当前 OOM score(越低越不易被 kill)
    cat /proc/$(pgrep mysqld)/oom_score_adj
    # 设置 MySQL 为 -500(最高保护),Redis 为 -300
    echo -500 | sudo tee /proc/$(pgrep mysqld)/oom_score_adj
    echo -300 | sudo tee /proc/$(pgrep redis-server)/oom_score_adj
    # (需写入 service 文件持久化,见下方)
  3. Systemd 服务文件加固(推荐)
    /etc/systemd/system/mysqld.service.d/oom.conf

    [Service]
    OOMScoreAdjust=-500
    MemoryLimit=1100M   # systemd 级别硬限制(内核 4.5+)

    /etc/systemd/system/redis.service.d/oom.conf

    [Service]
    OOMScoreAdjust=-300
    MemoryLimit=550M
    sudo systemctl daemon-reload

✅ 五、监控与告警(上线后必做)

  • 实时监控脚本(每5分钟检查)
    #!/bin/bash
    mem=$(free | awk '/Mem:/ {printf("%.0f"), $3/$2*100}')
    mysql_mem=$(ps aux --sort=-%mem | grep mysqld | head -1 | awk '{print $6/1024 "MB"}')
    redis_mem=$(ps aux --sort=-%mem | grep redis | head -1 | awk '{print $6/1024 "MB"}')
    echo "$(date): Mem:${mem}%, MySQL:${mysql_mem}, Redis:${redis_mem}"
    [ $mem -gt 90 ] && echo "ALERT: System memory >90%" | mail -s "OOM Warning" admin@example.com
  • 工具推荐htopglancesPrometheus + Grafana(轻量版)。

❌ 绝对禁止的操作

  • ❌ 不设 maxmemory(Redis 默认无上限 → 内存耗尽)
  • ❌ 不调 innodb_buffer_pool_size(默认可能 128MB,但其他缓存叠加仍爆)
  • ❌ 开启 performance_schema(2GB 下可吃掉 200MB+)
  • ❌ 同时开启 RDB + AOF(双持久化 → 内存+I/O 压力翻倍)
  • ❌ 使用 innodb_buffer_pool_instances > 1(小内存下反而增加开销)

✅ 最终效果预期

指标 目标值
系统空闲内存 ≥300MB(free -h
MySQL RSS 内存 ≈1050–1100MB
Redis RSS 内存 ≈520–560MB
mem_fragmentation_ratio (Redis) < 1.3
OOM Killer 触发次数 0(长期稳定)

💡 提示:若业务允许,优先考虑分离部署(MySQL 和 Redis 分在不同机器),或改用更轻量替代方案(如 SQLite + Redis,或 TiDB Lite)。2GB 是极限场景,务必做好降级预案(如 Redis 降级为本地缓存)。

需要我为你生成完整的 my.cnf / redis.conf 模板文件,或 systemd service 配置?欢迎随时提出 👇

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