在 2核4G 的服务器上部署 LNMP(Linux + Nginx + MySQL + PHP)并兼顾 Redis,内存资源非常紧张(可用内存约 3.2–3.5G,需预留系统、Nginx、PHP-FPM、内核缓存等)。优化目标是:避免 OOM Killer 杀进程、保障服务稳定、兼顾响应性能。以下是针对 MySQL 和 Redis 的精细化内存优化方案(基于主流版本:MySQL 8.0+ / Redis 7.x,OS 为 CentOS 8+/Ubuntu 22.04):
✅ 一、整体内存分配建议(总可用 ≈ 3.4G)
| 组件 | 建议分配内存 | 说明 |
|---|---|---|
| 操作系统 & 内核缓存 | ≥ 512MB | 必须保留,避免系统卡顿/OOM |
| Nginx + PHP-FPM | 300–500MB | pm=ondemand + 合理 pm.max_children=10–15(见后文) |
| MySQL | 1.0–1.4G ← 重点优化对象 | |
| Redis | 300–500MB ← 严格限制,禁用持久化或选轻量模式 | |
| 缓冲/预留 | ≥ 300MB | 应对突发流量、文件缓存、日志等 |
⚠️ 总和控制在 ≤ 3.2G,留足安全余量。
🐘 二、MySQL 内存优化(以 MySQL 8.0 为例)
🔧 关键参数调优(/etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf)
[mysqld]
# —— 全局内存 ——
# 总内存 ≈ 1.2G(示例值,按实际调整)
innodb_buffer_pool_size = 900M # ⭐ 最关键!设为物理内存的 25–30%(非 50%!),避免挤占其他服务
innodb_buffer_pool_instances = 2 # 匹配 CPU 核数,减少锁争用
# —— 连接与线程 ——
max_connections = 64 # 默认151太高!2C4G下64足够(监控 `show status like 'Threads_connected'` 调整)
wait_timeout = 60 # 空闲连接60秒断开,释放内存
interactive_timeout = 60
table_open_cache = 400 # 减少表缓存开销(默认2000过高)
tmp_table_size = 32M # 内存临时表上限(避免频繁磁盘临时表)
max_heap_table_size = 32M
# —— 日志与性能 ——
innodb_log_file_size = 128M # 日志文件大小(总 ib_logfile*2 = 256M),平衡恢复速度与写入性能
innodb_log_buffer_size = 4M # 日志缓冲区,够用即可
innodb_flush_log_at_trx_commit = 1 # 安全第一(如允许丢少量数据可设2,但不推荐生产)
sync_binlog = 1 # 同上,保证主从一致性
# —— 查询优化 ——
sort_buffer_size = 256K # 每连接排序缓冲(勿设过大!)
read_buffer_size = 128K
read_rnd_buffer_size = 256K
join_buffer_size = 256K
# —— 禁用不用功能(省内存)——
skip_log_error = ON # 如无需详细错误日志
performance_schema = OFF # ⚠️ 生产环境关闭!占用 100–200MB 内存
✅ 验证与监控命令:
# 查看实际内存使用(重点关注 buffer pool)
mysql -e "SHOW ENGINE INNODB STATUSG" | grep "Buffer pool"
mysql -e "SELECT * FROM sys.memory_global_total;" # 需启用 performance_schema(若开启)
# 监控连接数
mysql -e "SHOW STATUS LIKE 'Threads_connected';"
# 检查慢查询(避免大查询拖垮内存)
mysql -e "SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1;"
💡 技巧:
- 使用
mysqltuner.pl(Perl脚本)一键分析配置合理性:wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl perl mysqltuner.pl --host 127.0.0.1- 若业务读多写少,可适当增加
innodb_buffer_pool_size至 1.1G;若写密集,降低至 800M 并加大innodb_log_file_size。
🍭 三、Redis 内存优化(Redis 7.x)
🔧 关键配置(/etc/redis/redis.conf)
# —— 内存限制 —— ⭐ 强制设置!
maxmemory 400mb # 必须设置!防止吃光内存
maxmemory-policy allkeys-lru # 推荐:LRU驱逐,避免OOM;也可用 volatile-lru(仅驱逐带过期时间的key)
# —— 禁用持久化(节省CPU+内存)——
save "" # 禁用 RDB 快照
appendonly no # 禁用 AOF(除非强需求持久化)
# —— 连接与超时 ——
tcp-keepalive 300 # 保持连接活跃,及时清理僵尸连接
timeout 300 # 闲置5分钟断开
maxclients 256 # 合理限制客户端数
# —— 其他精简项 ——
lazyfree-lazy-eviction yes # 驱逐时异步释放内存(防阻塞)
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
activerehashing yes # 渐进式rehash,避免卡顿
✅ 进阶建议:
- 绝不使用
maxmemory-policy noeviction(会直接拒绝写入,导致业务失败); - 若需持久化 → 仅启用 AOF +
appendfsync everysec(比 always 内存/CPU 更友好),并确保aof-rewrite-incremental-fsync yes; - 使用
redis-cli --memkeys(需 Redis 7.0+)或redis-cli --bigkeys定期检查大 key; - PHP 中用
Predis或phpredis时,禁用长连接池(易泄漏),改用短连接或连接复用。
📊 监控命令:
redis-cli info memory | grep -E "(used_memory_human|maxmemory_human|mem_fragmentation_ratio)"
redis-cli info clients | grep connected_clients
# 实时观察内存变化
watch -n 1 'redis-cli info memory | grep used_memory_human'
🌐 四、协同优化(LNMP 整体联动)
| 组件 | 协同调优点 |
|---|---|
| PHP-FPM | pm = ondemand(非 static),pm.max_children = 12,pm.process_idle_timeout = 10s,pm.max_requests = 500(防内存泄漏) |
| Nginx | worker_processes 2; worker_connections 1024; client_body_buffer_size 16k; client_max_body_size 10m; 禁用 gzip_vary 等非必要模块 |
| 系统层 | vm.swappiness = 1(减少交换,但保留应急能力);echo 'vm.vfs_cache_pressure = 50' >> /etc/sysctl.conf(降低 inode/dentry 缓存压力) |
🚨 五、必须做的兜底措施
-
启用 OOM Killer 日志监控:
# 查看是否被杀过 dmesg -T | grep -i "killed process" # 持续监控(加入 cron 或 systemd timer) echo "$(date): $(free -h)" >> /var/log/memory.log -
配置
systemd内存限制(推荐):# /etc/systemd/system/mysqld.service.d/limit.conf [Service] MemoryLimit=1.3G# /etc/systemd/system/redis-server.service.d/limit.conf [Service] MemoryLimit=450M✅ systemd 会主动 kill 超限进程,比 OOM Killer 更可控。
-
定期巡检脚本(示例):
# /root/check_mem.sh free -h | awk '/Mem:/ {printf "MEM: %.1f%%n", $3/$2*100}' redis-cli info memory | awk -F':' '/used_memory_human/{gsub(/[^0-9.]/,"",$2); print "Redis:", $2, "MB"}' mysql -e "SELECT ROUND((@@innodb_buffer_pool_pages_data*16384)/1024/1024,1) AS 'BP_Used_MB';"
✅ 总结:2核4G 黄金配置速查表
| 参数 | 推荐值 | 备注 |
|---|---|---|
innodb_buffer_pool_size |
900M |
可根据业务读写比例微调 ±100M |
max_connections |
64 |
结合 show processlist 观察峰值 |
maxmemory (Redis) |
400mb |
必设!配合 allkeys-lru |
performance_schema |
OFF |
节省 150MB+ 内存 |
AOF/RDB |
全禁用(或仅 AOF everysec) | 持久化需求低时首选 |
PHP-FPM pm.max_children |
12 |
配合 ondemand 模式 |
✅ 最后提醒:
- 所有修改后 重启服务:
systemctl restart mysqld redis nginx php-fpm- 修改前备份配置:
cp /etc/my.cnf{,.bak}- 观察 24 小时:
top,htop,mysqladmin proc stat,redis-cli info- 业务低峰期操作,避免影响线上!
如需我帮你生成 完整可执行的配置文件模板(含注释)、一键检测脚本 或 针对 WordPress/Discuz 等常见应用的专项优化建议,欢迎随时提出 👇
CLOUD技术博