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

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


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

组件 建议内存上限 说明
MySQL ≤ 1.0–1.2G 核心数据库,需保证稳定性与基本性能
Redis ≤ 512MB 非持久化缓存场景;若需持久化(RDB/AOF),建议 ≤384MB 并关闭 save 或仅用 bgsave
PHP-FPM ≤ 600MB pm = staticpm = dynamic 合理配置(见后)
Nginx ~50MB 默认极轻量
系统/OS ≥ 500MB 内核、缓冲、SSH、日志等必需预留

⚠️ 关键原则

  • 禁止 MySQL + Redis 同时峰值占用 → 必须错峰或限流
  • 禁用 swap(或设 vm.swappiness=1:SSD 延迟高,swap 触发会导致服务卡死
  • 启用 oom_score_adj 降低非关键进程 OOM 优先级(如 echo -500 > /proc/$(pgrep redis)/oom_score_adj

🔧 一、MySQL(推荐 MySQL 8.0+ 或 Percona Server,避免 MariaDB 内存泄漏旧版本)

✅ 核心配置(/etc/my.cnf/etc/mysql/mysql.conf.d/mysqld.cnf

[mysqld]
# === 内存控制(最关键)===
innodb_buffer_pool_size = 896M     # 💡 占总内存 25%~28%,严禁 >1.1G!
innodb_buffer_pool_instances = 2   # 匹配 CPU 核数,减少锁争用
innodb_log_file_size = 64M        # 日志文件大小(默认 48M→64M 提升写性能,但不要过大)
innodb_log_buffer_size = 4M        # 足够小流量写入

# === 连接与查询优化 ===
max_connections = 100              # 默认151太高!按实际并发调(`show processlist` 观察)
wait_timeout = 60                  # 空闲连接超时(秒)
interactive_timeout = 60
query_cache_type = 0               # ❌ MySQL 8.0+ 已移除;5.7请务必关闭(严重锁竞争)
tmp_table_size = 32M
max_heap_table_size = 32M
table_open_cache = 400             # 适度降低(默认2000过高)

# === 日志与安全 ===
slow_query_log = ON
long_query_time = 2
log_error = /var/log/mysql/error.log
innodb_flush_log_at_trx_commit = 1  # 安全第一(=2 有丢数据风险,不推荐)

# === 其他瘦身项 ===
skip_log_bin                        # 关闭 binlog(除非主从/备份必需)
innodb_file_per_table = ON

📌 验证与监控

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

# 实时内存占用(应稳定在 900MB 左右)
ps aux --sort=-%mem | head -10 | grep mysqld

💡 进阶提示

  • 若业务以读为主且允许轻微延迟,可将 innodb_buffer_pool_size 设为 1024M,但需确保 PHP-FPM 不超 500MB;
  • 若纯静态博客/小 CMS(如 WordPress),896M 更稳妥;
  • 绝对避免 innodb_buffer_pool_size = 2G——极易触发 OOM。

🔧 二、Redis(推荐 Redis 7.x,启用 memory 策略防爆)

✅ 核心配置(/etc/redis/redis.conf

# === 内存限制(强制生效)===
maxmemory 480mb                      # 💡 留 32MB 缓冲给 Redis 自身开销
maxmemory-policy allkeys-lru         # 推荐:LRU 驱逐,避免 key 过期风暴
# maxmemory-policy volatile-lru      # 若仅对带过期时间的 key 缓存(更安全)

# === 持久化(谨慎选择)===
save ""                              # ❌ 彻底禁用 RDB 自动保存(避免 fork 大内存阻塞)
# save 900 1                          # 如需 RDB,注释掉上面,启用此行(低频)
stop-writes-on-bgsave-error yes

# === 安全与性能 ===
appendonly no                        # ❌ 关闭 AOF(AOF rewrite 极易 OOM!)
# appendonly yes; appendfsync everysec  # 若必须 AOF,请确保磁盘快且 `maxmemory` 更保守(≤384M)

# === 其他关键项 ===
lazyfree-lazy-eviction yes           # 驱逐时异步释放内存(防卡顿)
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
oom-score-adj no                     # 让系统优先 kill redis 而非 mysql(可选)

# === 网络与连接 ===
tcp-keepalive 300
timeout 300
maxclients 200                       # 匹配应用连接池设置

📌 启动前必做

# 1. 限制 Redis 进程最大 RSS 内存(内核级保险)
echo 'redis soft as 524288' | sudo tee -a /etc/security/limits.conf
echo 'redis hard as 524288' | sudo tee -a /etc/security/limits.conf
# (524288 KB = 512MB)

# 2. 检查是否启用 transparent huge pages(THP)→ 必须禁用!
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 加入 /etc/rc.local 或 systemd 启动脚本中持久化

📌 监控命令

redis-cli info memory | grep -E "(used_memory_human|maxmemory_human|mem_fragmentation_ratio)"
# 正常值:used_memory < 480mb,mem_fragmentation_ratio < 1.5

⚠️ 重要警告

  • appendonly yes 在 4G 机器上是“OOM 高危操作”,除非你使用 SSD 且 maxmemory ≤ 384MB
  • 避免 maxmemory-policy noeviction —— 写满直接拒绝请求,导致 PHP 报错;
  • 如果只是 Session 缓存,allkeys-lru 最安全。

🌐 三、协同优化(LNMP 整体平衡)

✅ PHP-FPM 配置(/etc/php/*/fpm/pool.d/www.conf

pm = static          # 避免 dynamic 的 fork 开销和内存波动
pm.max_children = 20 # 2核 × 10 = 20(每个 PHP 进程约 25–35MB)
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 1000  # 防止内存泄漏累积

php_admin_value[memory_limit] = 128M   # 单请求上限,勿设 512M!
php_admin_value[max_execution_time] = 30

✅ Nginx 轻量化

# /etc/nginx/nginx.conf
events {
    worker_connections 512;  # 无需 1024+
    use epoll;
}
http {
    client_max_body_size 10M;
    client_body_buffer_size 128k;
    client_header_buffer_size 1k;
    large_client_header_buffers 2 1k;
    # 关闭 access_log(或用 buffer+flush)减少 I/O
    access_log /var/log/nginx/access.log main buffer=64k flush=5s;
}

🛡️ 四、防御性运维建议

措施 命令/配置 作用
实时内存监控 htop, free -h, cat /proc/meminfo | grep -i "mem" 发现异常增长
OOM 日志检查 dmesg -T | grep -i "killed process" 确认是否被杀
MySQL 自动重启 systemctl edit mysqld[Service] Restart=on-failure 故障自愈
Redis 内存告警 redis-cli info memory | awk -F': ' '/used_memory:/ {if($2>450*1024*1024) print "ALERT"}' 加入 cron 每5分钟检测
日志轮转 sudo logrotate -f /etc/logrotate.d/mysql 防止 /var/log 填满

✅ 最终效果预期(2核4G)

场景 表现
日常负载(QPS 20–50) MySQL RSS ≈ 900MB,Redis ≈ 300MB,PHP-FPM ≈ 500MB,系统空闲 ≥ 800MB,响应稳定
突发流量(QPS 100+) Redis LRU 自动驱逐、MySQL 连接拒绝(而非崩溃)、Nginx 返回 503(可控降级)
磁盘压力 无 swap 使用、无频繁 bgsave/AOF rewrite、I/O wait < 5%

总结口诀

“MySQL 八九六,Redis 四八零;PHP 二十子,留足八百稳。”
—— 即:innodb_buffer_pool_size=896Mmaxmemory=480mbpm.max_children=20,系统预留 ≥800MB

如需我为你生成:

  • ✅ 完整的 my.cnf / redis.conf 配置文件(一键复制)
  • ✅ Shell 脚本自动校验内存分配合理性
  • ✅ Prometheus + Grafana 轻量监控模板
    欢迎随时提出,我可以立即为你定制 👇
未经允许不得转载:云知道CLOUD » 在2核4G的服务器上部署LNMP环境,如何优化MySQL和Redis的内存使用?