在2核4G的服务器上部署LNMP环境,如何优化MySQL和Redis的内存使用?

在 2核4G 的服务器上部署 LNMP(Linux + Nginx + MySQL + PHP)并共存 Redis,内存资源非常紧张(可用内存约 3.2–3.5G,需预留系统、Nginx、PHP-FPM 及缓冲),必须严格限制 MySQL 和 Redis 的内存占用,避免 OOM Kill。以下是经过生产验证的精细化优化方案:


✅ 一、总体内存分配建议(总可用 ≈ 3.4G)

组件 建议内存上限 说明
MySQL 1.0–1.2G 主要消耗者,需精调缓冲池与连接数
Redis 0.6–0.8G 启用 LRU/LFU 驱逐 + maxmemory-policy
PHP-FPM 0.4–0.6G pm = staticondemand,max_children ≤ 20
Nginx < 0.1G 通常仅占用几十 MB
系统/OS ≥ 0.5G 内核、缓存、预留安全余量

⚠️ 关键原则MySQL + Redis + PHP-FPM ≤ 2.5G,为系统和突发负载留足余量。


🐘 二、MySQL 优化(以 MySQL 8.0 为例,推荐使用)

1. 核心内存参数(my.cnf)

[mysqld]
# —— 内存相关 ——
innodb_buffer_pool_size = 1024M      # ⚠️ 最关键!设为物理内存的 25–30%(4G×0.25=1G)
innodb_buffer_pool_instances = 2      # 匹配 CPU 核数,减少锁争用

# 连接与线程(严控!)
max_connections = 50                  # 默认151太浪费,按实际并发调低
wait_timeout = 60                     # 空闲连接60秒断开
interactive_timeout = 60

# 日志与临时表(减小内存压力)
innodb_log_file_size = 64M            # 默认 48M→64M,平衡性能与恢复时间
innodb_log_buffer_size = 2M           # 足够,避免过大
tmp_table_size = 32M                  # 与 max_heap_table_size 一致
max_heap_table_size = 32M
sort_buffer_size = 256K               # 每连接分配,勿超 512K
join_buffer_size = 256K
read_buffer_size = 128K
read_rnd_buffer_size = 256K

# 其他关键项
skip_name_resolve = ON                # 禁用 DNS 解析,提速连接
innodb_flush_method = O_DIRECT        # 避免双缓冲(Linux 下推荐)
innodb_io_capacity = 200             # SSD 设为 200–400,HDD 设为 100
innodb_io_capacity_max = 400

2. 必须禁用的功能(节省内存)

# 关闭查询缓存(MySQL 8.0+ 已移除,5.7 需显式关闭)
query_cache_type = 0
query_cache_size = 0

# 禁用 Performance Schema(调试时再开)
performance_schema = OFF

# 禁用 InnoDB 全文索引(如不用)
innodb_ft_enable_stopword = OFF

3. 运行时检查与验证

# 查看实际 buffer pool 使用率(健康值 70–95%)
mysql -e "SHOW ENGINE INNODB STATUSG" | grep "Buffer pool hit rate"

# 检查连接数峰值(避免 max_connections 过大)
mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_created';"  # 若持续增长,说明连接未复用

# 监控内存:top -p $(pgrep mysqld) → 看 RES 列(应接近 innodb_buffer_pool_size + 少量开销)

🍵 三、Redis 优化(推荐 Redis 7.x)

1. redis.conf 关键配置

# —— 内存限制 ——
maxmemory 768mb                       # ⚠️ 强制上限!必须设置!
maxmemory-policy allkeys-lru          # 推荐:LRU 驱逐所有 key(或 volatile-lru 如果只对带过期的 key 驱逐)
# maxmemory-samples 5                 # 默认即可,无需调高

# —— 连接与超时 ——
maxclients 200                          # 严格限制客户端数(默认 10000 太危险)
timeout 300                             # 空闲连接5分钟断开
tcp-keepalive 60                        # 心跳保活

# —— 持久化(内存敏感场景慎用 RDB/AOF)——
save ""                                 # ❌ 禁用 RDB 自动快照(避免 fork 内存翻倍)
# 若需持久化,改用:
# save 3600 1                           # 1小时至少1次变更才保存(降低频率)

appendonly no                           # ❌ 禁用 AOF(写入性能好,但会额外内存+磁盘IO)
# appendfsync everysec                 # 如启用,务必设为 everysec(非 always)

# —— 其他 ——
lazyfree-lazy-eviction yes              # 驱逐 key 时异步释放内存(防卡顿)
lazyfree-lazy-expire yes                # 过期 key 异步删除
lazyfree-lazy-server-del yes
oom-score-adj yes                       # 让内核更倾向 kill redis 而非其他进程(OOM 时)

2. PHP 应用层配合

  • 使用连接池(如 predis + PredisConnectionAggregatePredisClusterphpredispconnect);
  • 绝不使用 new Redis() 每次新建连接,改用长连接或连接池;
  • 设置合理的 key 过期时间(EXPIRE),避免内存堆积;
  • 定期用 redis-cli --bigkeys 检查大 key 并拆分。

3. 监控命令

redis-cli info memory | grep -E "(used_memory_human|maxmemory_human|mem_fragmentation_ratio)"
# used_memory_human < maxmemory_human ✔️  
# mem_fragmentation_ratio 接近 1.0–1.5(>1.5 表示内存碎片高)

redis-cli config get maxmemory  # 确认生效

🔧 四、协同优化与系统级加固

  1. PHP-FPM 严格限流(/etc/php-fpm.d/www.conf)

    pm = static
    pm.max_children = 12           # 每个进程约 30–50MB,12×40MB≈480MB
    pm.start_servers = 4
    pm.min_spare_servers = 2
    pm.max_spare_servers = 6
    pm.max_requests = 500          # 防止内存泄漏
  2. 启用 Linux 内存回收机制

    # 降低 swappiness(减少 swap 使用,优先回收缓存)
    echo 'vm.swappiness=1' >> /etc/sysctl.conf
    sysctl -p
    
    # 启用透明大页(THP)→ **必须禁用!**(MySQL/Redis 对 THP 敏感,导致延迟抖动)
    echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled
    echo 'never' > /sys/kernel/mm/transparent_hugepage/defrag
    # 加入 /etc/rc.local 永久生效
  3. 添加 OOM Killer 保护(可选)

    # 降低 MySQL 被 kill 优先级(数值越小越不易被杀)
    echo -500 > /proc/$(pgrep mysqld)/oom_score_adj
    echo -400 > /proc/$(pgrep redis-server)/oom_score_adj
  4. 日志与监控(必备)

    • 使用 htop / glances 实时监控内存;
    • 检查 /var/log/mysql/error.log/var/log/redis/redis-server.log
    • 设置告警:当 free -havailable < 500M 时触发通知。

🚫 五、绝对禁止的操作

  • ❌ 不设 maxmemory(Redis 无限制吃光内存);
  • innodb_buffer_pool_size > 1.2G(留足给系统和其他服务);
  • ❌ 开启 query_cache(MySQL 5.7)或 performance_schema(无调试需求时);
  • ❌ 使用 AOF + always 或高频 RDB save(fork 导致瞬时内存翻倍);
  • pm = dynamicmax_children 过大(易触发 OOM)。

✅ 六、上线前 Checklist

  • [ ] free -h 确认空闲内存 ≥ 800MB;
  • [ ] mysqltuner.pl 扫描(重点关注 InnoDB Buffer Pool Size 建议);
  • [ ] redis-cli info memory 验证 maxmemory 生效;
  • [ ] ab -n 1000 -c 50 http://localhost/ 压测,观察 top 中各进程 RES 是否稳定;
  • [ ] 模拟 1 小时持续请求,检查 dmesg | grep -i "killed process" 是否有 OOM 记录。

如需进一步定制(如具体业务类型:WordPress?API 服务?高读/高写?),我可提供针对性参数模板。也可为你生成一键优化脚本(含安全备份、参数校验、重启逻辑)。欢迎补充场景细节 👇

未经允许不得转载:CLOUD云枢 » 在2核4G的服务器上部署LNMP环境,如何优化MySQL和Redis的内存使用?