在 2 核 4G(约 3.8GB 可用内存)的服务器上部署 LNMP,内存资源非常紧张,必须对 MySQL 和 Redis 进行精细调优,避免 OOM(Out Of Memory)导致服务崩溃。以下是针对该配置的优化建议:
一、总体内存规划(参考)
| 组件 | 建议最大占用 | 说明 |
|---|---|---|
| Linux 系统 + Nginx + PHP-FPM | 600–800 MB | 含内核、系统进程、Web 服务 |
| MySQL | ≤ 1.5 GB | 核心配置项调整 |
| Redis | ≤ 1.2 GB | 根据数据量设定 maxmemory |
| 预留缓冲 | ≥ 300 MB | 防止突发负载导致 OOM |
✅ 总内存需求 ≈ 800 + 1500 + 1200 = 3500 MB < 4096 MB(留有余地)
二、MySQL 内存优化(以 MariaDB/MySQL 5.7+ 为例)
1. 关键配置项(my.cnf 或 mysqld.cnf)
[mysqld]
# 基础设置
innodb_buffer_pool_size = 1G # 占物理内存 25%~40%,优先分配给 InnoDB
innodb_log_file_size = 256M # 日志大小,减少刷盘压力
innodb_flush_log_at_trx_commit = 2 # 性能与安全性平衡(生产可设为 1,但需权衡)
# 连接控制(防连接风暴)
max_connections = 150 # 默认 151,适当降低
thread_cache_size = 32 # 缓存线程,减少创建开销
# 临时表与排序
tmp_table_size = 64M # 内存临时表上限
max_heap_table_size = 64M # 同上
sort_buffer_size = 2M # 每连接独立,注意 max_connections * sort_buffer_size 不能过大
# 查询缓存(MySQL 8.0 已移除;5.7 中建议关闭)
query_cache_type = 0
query_cache_size = 0
# 其他安全项
skip-name-resolve # 禁用 DNS 解析提速登录
performance_schema = OFF # 非调试场景可关闭
🔍 验证命令:
mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';" # 若读命中率 > 99%,说明 buffer_pool 设置合理
2. 注意事项
- ❌ 不要设置
key_buffer_size(MyISAM 已少用),除非有旧 MyISAM 表。 - ⚠️
join_buffer_size/read_buffer_size等每连接变量需谨慎,避免max_connections × buffer_size超限。 - 使用
mysqltuner.pl工具定期分析并给出动态建议。
三、Redis 内存优化
1. 核心配置(redis.conf)
# 内存限制(最关键!)
maxmemory 1200mb # 略小于 1.2GB,留出余量
# 淘汰策略(根据业务选择)
maxmemory-policy allkeys-lru # 推荐:LRU 淘汰最近最少使用键
# 或 volatile-lru(仅淘汰带 TTL 的键)
# 或 noeviction(严格防溢出,但可能阻塞写入)
# 内存碎片管理
activedefrag yes
active-memory-defrag-threshold-low 60
active-memory-defrag-threshold-high 100
# 持久化(根据 RDB/AOF 取舍)
save 900 1 # 1 分钟至少 1 个 key 变化时触发 RDB
# aof-enabled yes
# aof-fsync everysec # 若选 AOF,注意磁盘 IO 影响
2. 监控与调优技巧
- 实时查看内存使用:
redis-cli INFO memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio" - 若
mem_fragmentation_ratio > 1.5,启用activedefrag自动整理碎片。 - 避免存储大对象(如 >1MB 的字符串),考虑分片或压缩。
四、系统级协同优化
1. 限制 PHP-FPM 内存
# /etc/php/8.x/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 20 # 20 个进程 × ~50MB = 1GB
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
request_terminate_timeout = 30s # 防止脚本死循环占内存
2. 开启 Swap(谨慎使用)
# 创建 1GB swap(仅作应急,避免频繁交换导致卡顿)
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 调整 swappiness(降低交换倾向)
echo "vm.swappiness=10" >> /etc/sysctl.conf
sysctl -p
3. 使用 cgroups 限制(进阶)
若支持 systemd/cgroup v2,可为 MySQL/Redis 设置内存上限:
# /etc/systemd/system/mysqld.service.d/override.conf
[Service]
MemoryMax=1.5G
MemoryHigh=1.3G
五、验证与监控建议
-
压力测试后观察:
htop # 实时看内存/CPU free -h # 检查 buff/cache 是否异常高 vmstat 1 # 观察 si/so(swap in/out) -
告警阈值:
- MySQL 内存 > 1.6GB → 报警
- Redis 内存 > 1.1GB → 报警
free内存 < 200MB → 紧急处理
-
长期优化:
- 定期清理慢查询(
slow_query_log) - 分析 Redis 大 Key(
--bigkeys工具) - 考虑将热点数据预热到 buffer_pool
- 定期清理慢查询(
✅ 总结:在 2C4G 环境下,“小步快跑、保守配置、持续监控” 是核心原则。优先保证 MySQL 的 InnoDB buffer pool 和 Redis 的 maxmemory 不超配,再配合系统级限制与 swap 兜底,即可稳定运行 LNMP。
如需具体某一步的详细操作(如编译参数、Docker 部署调优等),欢迎进一步说明环境细节。
轻量云Cloud