2G 内存跑 LNMP(Linux + Nginx + MySQL/MariaDB + PHP)在现在的标准下确实属于“极限操作”。如果是生产环境,我首先建议是加内存或者上容器化集群分摊负载;但如果受限于预算或测试需求,必须在这台机器上跑起来,那就得把每一兆内存都抠出来用。
核心思路就三个:Nginx 抗并发、PHP 精简扩展、MySQL 极致压缩。
下面是一套经过实战验证的、偏向保守但稳定的配置方案:
1. Linux 系统层优化
别装桌面环境,直接用最小化安装的 CentOS Stream 8/9 或 Ubuntu Server LTS。
Swap(交换分区)是救命稻草
2G 物理内存一旦爆满,进程直接 OOM Kill。必须开启 Swap,但不要太大,防止磁盘 IO 拖垮性能。
- 建议大小:2G – 4G。
- 调整 swappiness:让内核更倾向于使用物理内存,只有在实在不够时才用 Swap。
# 查看当前值 cat /proc/sys/vm/swappiness # 临时修改为 10 sysctl vm.swappiness=10 # 永久修改,编辑 /etc/sysctl.conf,添加 vm.swappiness=10
关闭不必要的服务
systemctl disable firewalld iptables # 如果用云厂商安全组,本地防火墙可关
systemctl disable auditd
systemctl stop postfix
2. Nginx 配置:轻量且高效
Nginx 本身很省内存,主要控制 Worker 进程数和连接数。
- Worker 进程数:设为 CPU 核心数即可,2G 内存的服务器通常是 2 核或 4 核。
- Keepalive 超时时间:适当缩短,减少空闲连接占用。
- Buffer 设置:调小
client_body_buffer_size和proxy_buffer_size,默认可能偏大。
worker_processes auto; # 自动匹配 CPU 核心数
events {
worker_connections 1024; # 2G 内存别开太高,512-1024 足够
use epoll;
}
http {
keepalive_timeout 65;
# 关键:减小缓冲区,节省内存
client_body_buffer_size 1k;
client_header_buffer_size 1k;
large_client_header_buffers 2 1k;
proxy_buffer_size 1k;
proxy_buffers 4 4k;
# 开启 gzip 压缩,节省带宽并减轻后端压力
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
types_hash_max_size 2048;
}
3. PHP-FPM 配置:重中之重
PHP 是最吃内存的组件。2G 内存下,绝对不能让 PHP 产生大量子进程。
版本选择:强烈建议使用 PHP 7.4 或 PHP 8.0/8.1(配合 OPcache)。PHP 8 虽然启动稍慢,但内存管理有优化,且 JIT 对计算密集型任务友好。对于 Web 应用,PHP 7.4 的稳定性与资源占用平衡较好。
FPM Pool 配置 (www.conf)
采用 ondemand 模式,平时不占内存,来了请求再 fork。
[www]
user = www-data
group = www-data
listen = /run/php/php-fpm.sock
; 关键:动态模式
pm = ondemand
pm.max_children = 5 ; 最大同时处理 5 个请求,够了
pm.start_servers = 2 ; 启动 2 个预派生进程
pm.min_spare_servers = 1 ; 最少保留 1 个
pm.max_spare_servers = 3 ; 最多保留 3 个
pm.process_idle_timeout = 10s ; 空闲 10 秒后回收,快速释放内存
; 关键:限制每个子进程内存
php_admin_value[memory_limit] = 64M ; 单个 PHP 脚本最大内存 64MB
OPcache 配置 (php.ini)
开启 OPcache 能极大降低 CPU 和内存开销,因为不需要每次解析 PHP 源码。
opcache.enable=1
opcache.memory_consumption=64 ; 分配 64MB 给 OPcache,足够中小型项目
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60 ; 60 秒检查一次文件更新,开发环境可设 0,生产务必大于 0
opcache.validate_timestamps=1
4. MySQL/MariaDB 配置:极度克制
这是最容易 OOM 的地方。MySQL 默认配置会预留大量 Buffer Pool。
强烈建议:如果数据量不大(< 1GB),考虑用 SQLite 替代 MySQL,或者用 MariaDB 代替 MySQL(MariaDB 在某些场景下内存略低)。如果必须用 MySQL,请按以下参数调整 /etc/my.cnf 或 /etc/mysql/my.cnf:
[mysqld]
# 基础设置
innodb_buffer_pool_size = 128M ; 关键!不要超过总内存的 50%,128M-256M 足够
innodb_log_file_size = 32M
innodb_flush_method = O_DIRECT
query_cache_type = 0 ; MySQL 5.7+ 已废弃,MariaDB 10.1+ 也建议关闭,避免锁竞争和内存碎片
query_cache_size = 0
# 连接数限制
max_connections = 50 ; 2G 内存开 100 个连接必死,50 足够
thread_stack = 192K ; 减小线程栈大小
# 其他优化
table_open_cache = 200 ; 减少文件描述符打开数量
sort_buffer_size = 256K ; 排序缓冲
read_buffer_size = 256K ; 读缓冲
join_buffer_size = 256K ; 连接缓冲
# 字符集
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
注意:innodb_buffer_pool_size 是内存大户。如果数据库表很小,甚至可以降到 64M。
5. 额外建议:架构层面的“省钱”技巧
- 静态资源分离:图片、CSS、JS 全部上传到 OSS/COS/S3,并在 Nginx 配置中直接返回 CDN 地址或XX到对象存储,不要让 PHP 去读取这些文件,也不要用 Nginx 做静态文件的缓存盘。
- 使用 Redis 做简单缓存:如果只有 2G 内存,Redis 也可以装,但配置要小。
maxmemory 64mb maxmemory-policy allkeys-lru用它来缓存数据库查询结果,减少 MySQL 压力。
- 监控告警:安装
htop和nmon,或者简单的 shell 脚本监控内存使用。当内存使用率持续超过 85% 时,手动重启 php-fpm 或清理缓存。 - 应用代码优化:
- 避免在循环中查库。
- 使用 Composer 自动加载,而不是手写 include。
- 如果可能,将非实时任务(如发邮件、生成报表)通过消息队列异步处理,或者干脆做成定时任务 cron job,避免阻塞 PHP-FPM 进程。
总结 checklist
| 组件 | 关键动作 |
|---|---|
| OS | 最小化安装,开启 2G Swap,swappiness=10 |
| Nginx | worker_connections 1024,减小 buffer,开启 gzip |
| PHP | FPM 用 ondemand 模式,max_children=5,memory_limit=64M,开启 OPcache |
| MySQL | innodb_buffer_pool_size=128M,max_connections=50,关闭 query_cache |
| 整体 | 静态资源上 OSS,代码层面优化 SQL |
这套配置能在 2G 内存服务器上稳定运行一个日均 PV 几千到一两万的 WordPress 或小型 CMS 网站。如果流量更大,唯一的出路就是升级硬件或拆分服务。
云技术博客