在 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 = static 或 ondemand,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+PredisConnectionAggregatePredisCluster或phpredis的pconnect); - 绝不使用
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 # 确认生效
🔧 四、协同优化与系统级加固
-
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 # 防止内存泄漏 -
启用 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 永久生效 -
添加 OOM Killer 保护(可选)
# 降低 MySQL 被 kill 优先级(数值越小越不易被杀) echo -500 > /proc/$(pgrep mysqld)/oom_score_adj echo -400 > /proc/$(pgrep redis-server)/oom_score_adj -
日志与监控(必备)
- 使用
htop/glances实时监控内存; - 检查
/var/log/mysql/error.log和/var/log/redis/redis-server.log; - 设置告警:当
free -h中available < 500M时触发通知。
- 使用
🚫 五、绝对禁止的操作
- ❌ 不设
maxmemory(Redis 无限制吃光内存); - ❌
innodb_buffer_pool_size > 1.2G(留足给系统和其他服务); - ❌ 开启
query_cache(MySQL 5.7)或performance_schema(无调试需求时); - ❌ 使用
AOF + always或高频RDB save(fork 导致瞬时内存翻倍); - ❌
pm = dynamic且max_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云枢