在 2核4GB 内存 的服务器上同时运行 MySQL(作为数据库)和 Nginx(作为 Web 服务器/反向X_X),属于典型的轻量级生产或中高流量测试环境。内存资源紧张(尤其 MySQL 默认配置偏“重”),必须精细化调优,否则极易出现 OOM(被系统 kill)、MySQL 崩溃、Nginx 502/504 或响应延迟等问题。
以下是关键优化方向与具体参数建议(基于主流版本:MySQL 8.0+、Nginx 1.18+、Linux kernel ≥ 5.x):
✅ 一、全局原则(必做)
- 禁用 swap(或严格限制):
sudo swapoff -a(临时),并注释/etc/fstab中 swap 行。
⚠️ 原因:MySQL 对 swap 敏感,一旦触发 swap,性能断崖式下降甚至 hang 死。 - 启用
vm.swappiness=1(非 0!避免内核过度回收缓存):echo 'vm.swappiness=1' | sudo tee -a /etc/sysctl.conf sudo sysctl -p - 限制 MySQL + Nginx 总内存占用 ≤ 3.2GB(预留 0.8GB 给 OS、PHP/Python 应用、内核缓存等)。
✅ 二、MySQL 优化(核心:大幅降低内存占用)
| 参数 | 推荐值 | 说明 |
|---|---|---|
innodb_buffer_pool_size |
1.2G ~ 1.6G(≤ 40% 总内存) | ⚠️ 最关键!默认 128M 太小,但设太大(如 2G+)会导致 Nginx/OOM。建议 1.4G(即 1472M)。✅ 配置后需重启 MySQL。 |
innodb_log_file_size |
64M ~ 128M | 日志文件大小,配合 innodb_log_files_in_group=2(默认)。避免过大(影响恢复时间)或过小(频繁 checkpoint)。 |
max_connections |
100 ~ 150 | 默认 151,每个连接约 2~3MB 内存(含线程栈、sort buffer 等)。100 连接 ≈ 200–300MB 内存。按实际并发需求设(如 PHP-FPM 并发数 × 1.5)。 |
sort_buffer_size |
256K ~ 512K | 每连接独占!默认 2M × 150 连接 = 300MB 内存浪费。设为 256K 即可满足多数排序需求。 |
read_buffer_size / read_rnd_buffer_size |
128K / 256K | 同上,避免 per-connection 内存爆炸。 |
tmp_table_size / max_heap_table_size |
32M ~ 64M | 控制内存临时表上限,防止大查询耗尽内存。 |
innodb_buffer_pool_instances |
2 | 匹配 CPU 核数(2核),减少锁争用。 |
innodb_flush_method |
O_DIRECT(Linux) |
绕过 OS 缓存,避免双重缓存(InnoDB 自己管理 buffer pool)。 |
query_cache_type |
0(禁用) | MySQL 8.0+ 已移除,5.7+ 强烈建议关闭(线程竞争严重)。 |
skip_name_resolve |
ON | 跳过 DNS 反查,提升连接速度,减少失败风险。 |
📌 my.cnf 示例片段(/etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf):
[mysqld]
# 内存控制
innodb_buffer_pool_size = 1472M
innodb_buffer_pool_instances = 2
innodb_log_file_size = 128M
max_connections = 120
sort_buffer_size = 256K
read_buffer_size = 128K
read_rnd_buffer_size = 256K
tmp_table_size = 64M
max_heap_table_size = 64M
# 性能与安全
innodb_flush_method = O_DIRECT
skip_name_resolve = ON
innodb_file_per_table = ON
innodb_flush_log_at_trx_commit = 1 # 保证 ACID(若允许少量丢失,可设 2)
🔁 修改后操作:
sudo systemctl stop mysql # 若修改了 innodb_log_file_size,需先删除旧日志(/var/lib/mysql/ib_logfile*) sudo rm -f /var/lib/mysql/ib_logfile* sudo systemctl start mysql
✅ 三、Nginx 优化(轻量、稳定、抗并发)
| 参数 | 推荐值 | 说明 |
|---|---|---|
worker_processes |
2 | 匹配 CPU 核数(auto 也可,但显式写 2 更清晰)。 |
worker_connections |
1024 ~ 2048 | 每 worker 最大连接数。总并发 = 2 × 1024 = 2048,足够中小流量。 |
worker_rlimit_nofile |
65536 | 提升单进程打开文件数限制(需同步调系统 limit)。 |
events.use |
epoll(Linux 默认) |
无需修改。 |
keepalive_timeout |
30 ~ 60s | 不宜过长(浪费连接),也不宜过短(增加 TCP 开销)。 |
client_max_body_size |
10M(按需调整) | 防止大上传耗尽内存。 |
gzip |
开启(gzip on; gzip_types …) | 减少传输体积,降低带宽和响应时间(CPU 开销低,2核完全够)。 |
proxy_buffering |
on(反向X_X时) | 避免后端慢导致 Nginx worker 阻塞。 |
📌 nginx.conf 关键段示例:
user www-data;
worker_processes 2;
worker_rlimit_nofile 65536;
events {
use epoll;
worker_connections 2048;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
types_hash_max_size 2048;
# Gzip
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Client limits
client_max_body_size 10M;
client_header_timeout 10;
client_body_timeout 10;
send_timeout 10;
# Proxy buffers (if proxying to PHP/Node/etc)
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
include sites-enabled/*;
}
📌 系统级文件句柄限制(必须同步设置):
# 编辑 /etc/security/limits.conf
echo -e "www-data soft nofile 65536nwww-data hard nofile 65536" | sudo tee -a /etc/security/limits.conf
echo -e "* soft nofile 65536n* hard nofile 65536" | sudo tee -a /etc/security/limits.conf
# 确保 systemd 服务继承(/etc/systemd/system/nginx.service.d/override.conf):
sudo mkdir -p /etc/systemd/system/nginx.service.d
echo -e "[Service]nLimitNOFILE=65536" | sudo tee /etc/systemd/system/nginx.service.d/override.conf
sudo systemctl daemon-reload
✅ 四、协同与监控建议
-
进程内存监控(实时):
# 查看各进程 RSS 内存(重点关注 mysqld, nginx: master/workers) ps -eo pid,user,%mem,vsz,rss,comm --sort=-rss | head -15 free -h # 看整体内存使用 -
MySQL 内存估算工具:
使用 MySQL Memory Calculator 输入你的配置,验证总内存是否超限。 -
启用慢查询日志(MySQL):
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; SET GLOBAL log_queries_not_using_indexes = OFF; -- 按需开启 -
Nginx 日志切割 & 错误监控:
关注error.log中的* upstream timed out(504)、* connect() failed(502)等,定位后端瓶颈。 -
应用层配合(关键!):
- PHP-FPM:
pm = static,pm.max_children = 20~30(每个 child ≈ 20–40MB); - 禁用不必要的 WordPress 插件 / Laravel debugbar / 全局 Eager Loading;
- 数据库查询务必加索引,避免
SELECT *和全表扫描。
- PHP-FPM:
❌ 避免踩坑
- ❌ 不要将
innodb_buffer_pool_size设为2G+(留足给 Nginx + OS); - ❌ 不要开启
query_cache(MySQL 5.7+ 已废弃,且有严重锁问题); - ❌ 不要让 Nginx
worker_connections过高(如 8192)而忽略ulimit未调; - ❌ 不要在同一台机器跑 Redis/Memcached(除非极轻量且明确需要);
- ❌ 不要忽略磁盘 I/O:确保 MySQL 数据目录在 SSD,
/var/log不占满根分区。
✅ 附:一键检查脚本(快速诊断)
#!/bin/bash
echo "=== 内存总览 ==="
free -h
echo -e "n=== MySQL 内存估算(近似)==="
mysql -Nse "SELECT ROUND((@@innodb_buffer_pool_size + @@key_buffer_size + @@query_cache_size + @@max_connections * (@@sort_buffer_size + @@read_buffer_size + @@read_rnd_buffer_size + @@join_buffer_size + @@thread_stack + @@tmp_table_size))/1024/1024, 1) AS MB;"
echo -e "n=== Nginx 进程内存 ==="
ps -o pid,user,vsz,rss,comm -C nginx | sort -k4nr
echo -e "n=== 当前连接数 ==="
ss -s | grep -E "(tcp|UDP)"
如需进一步优化,可提供:
mysqltuner.pl输出结果top或htop截图(内存/CPU 占用)- 业务类型(WordPress?API 服务?静态站?)
- 日均 PV / 并发请求峰值
我可以为你定制更精准的参数方案 👇
需要我帮你生成完整的 my.cnf + nginx.conf 可部署文件吗?
云计算HECS