在 2 核 CPU、2GB 内存的服务器上同时运行 Docker、MySQL 和 Redis,属于典型的资源受限环境。如果不进行针对性优化,极易出现内存溢出(OOM)导致服务被系统杀死,或者磁盘 I/O 瓶颈。
以下是针对该配置的关键优化方案,分为Docker 引擎层、操作系统层、MySQL 层和Redis 层四个维度:
1. Docker 引擎层优化
Docker 守护进程本身会占用一定内存,且容器默认的资源限制需要手动收紧。
-
限制 Docker 守护进程内存:
编辑/etc/docker/daemon.json,限制 Docker 自身使用的内存上限,防止其挤占应用内存。{ "default-ulimits": { "nofile": { "Name": "nofile", "Hard": 65535, "Soft": 65535 } }, "log-driver": "json-file", "log-opts": { "max-size": "50m", "max-file": "3" } }注:日志文件必须限制大小,否则 2G 内存很快会被日志撑爆。
-
设置容器资源限制(Cgroups):
在启动 MySQL 和 Redis 容器时,务必通过--memory和--cpus参数硬限制资源,不要使用默认值(无限制)。推荐启动命令示例:
# MySQL: 限制内存 800MB,CPU 1.0 核 docker run -d --name mysql --memory="800m" --memory-swap="800m" --cpus="1.0" -e MYSQL_ROOT_PASSWORD=your_password -v /data/mysql:/var/lib/mysql mysql:8.0 # Redis: 限制内存 400MB,CPU 0.5 核 docker run -d --name redis --memory="400m" --memory-swap="400m" --cpus="0.5" redis:alpine计算逻辑:2G 总内存 – Docker 开销 (约 200M) – 预留给宿主机 (约 200M) = 1.6G 可用。MySQL 给 800M,Redis 给 400M,剩余 400M 作为缓冲。
2. 操作系统层优化
Linux 内核参数对数据库性能影响巨大,特别是 Swap 交换分区。
-
禁用或严格限制 Swap(关键):
在 2G 内存环境下,一旦触发 Swap,MySQL/Redis 的随机读写延迟会剧增,导致服务假死。- 方案 A(推荐):如果可能,完全关闭 Swap (
swapoff -a)。因为一旦 OOM,直接杀掉进程比卡顿要好控制。 - 方案 B(保守):如果必须保留 Swap,调整
vm.swappiness为极低值(如 1),让系统优先使用物理内存。# 临时生效 sysctl vm.swappiness=1 # 永久生效 echo "vm.swappiness=1" >> /etc/sysctl.conf
- 方案 A(推荐):如果可能,完全关闭 Swap (
-
调整 TCP/IP 参数:
增加连接队列长度,防止高并发下连接重置。# 临时生效 sysctl -w net.core.somaxconn=1024 sysctl -w net.ipv4.tcp_max_syn_backlog=2048 -
文件系统挂载选项:
如果是云服务器的数据盘,挂载时添加noatime参数,减少磁盘写入元数据的开销。mount -o remount,noatime /dev/sdaX /mnt/data
3. MySQL 深度优化
MySQL 是内存大户,默认配置通常是为多核大内存设计的,必须大幅调低。
-
核心参数修改 (
my.cnf):
建议将配置文件放在/etc/my.cnf或 Docker 卷映射的配置文件中。[mysqld] # 基础设置 port = 3306 datadir = /var/lib/mysql # 内存相关 (最关键) innodb_buffer_pool_size = 400M # 建议设为可用内存的 25%-30%,此处留 400M 给 OS 和其他进程 innodb_log_file_size = 64M # 减小日志文件大小,加快崩溃恢复 innodb_flush_method = O_DIRECT # 绕过 OS 缓存,避免双重缓存浪费内存 # 连接与线程 max_connections = 100 # 根据业务量适当调整,2G 内存不宜过大 thread_cache_size = 10 # 减少线程创建开销 # 其他优化 query_cache_type = 0 # MySQL 8.0+ 已移除 Query Cache,旧版本建议关闭 skip-name-resolve # 禁止 DNS 解析,提升连接速度 -
字符集与存储引擎:
确保使用utf8mb4但注意索引大小。InnoDB 是唯一推荐的引擎。
4. Redis 深度优化
Redis 依赖内存速度,需防止内存碎片和持久化带来的抖动。
-
核心参数修改 (
redis.conf):# 内存限制 maxmemory 400mb # 必须与 Docker 启动时的 --memory 保持一致或略小 maxmemory-policy allkeys-lru # 当内存满时,淘汰最近最少使用的键,防止 OOM # 持久化策略 (AOF vs RDB) # 2G 服务器建议主要用 RDB 快照,AOF 频率设低或关闭,减少 IO 压力 save 900 1 # 15 分钟有 1 个 key 变化则保存 appendonly no # 生产环境若对实时性要求不高,可关闭 AOF 以节省 IO aof-load-truncated yes # 网络 tcp-backlog 511 timeout 300 -
内存碎片处理:
开启自动碎片整理(Redis 4.0+):activedefrag yes active-dfrag-memory-limit 128mb
5. 监控与兜底策略
在如此小的资源池上,“预防”优于“修复”。
- 配置 OOM Killer 保护:
虽然我们无法阻止 OOM,但可以观察日志。如果频繁发生,说明分配给容器的内存总和过高,需进一步压缩。dmesg | grep -i "killed process" - 监控工具:
安装轻量级监控(如cAdvisor或简单的 Shell 脚本),监控内存使用率。一旦超过 85% 立即报警。 - 备份策略:
由于资源紧张,不要在高峰期执行全量备份。建议使用mysqldump配合--single-transaction并在低峰期运行,或者利用 MySQL 的 Binlog 增量备份。
总结配置清单
| 组件 | 关键动作 | 推荐数值/参数 |
|---|---|---|
| OS | 关闭 Swap 或降低优先级 | vm.swappiness=1 或 swapoff |
| Docker | 限制容器资源 | MySQL: 800M RAM, 1.0 CPU; Redis: 400M RAM, 0.5 CPU |
| MySQL | 缩小 Buffer Pool | innodb_buffer_pool_size = 400M |
| Redis | 设置最大内存策略 | maxmemory 400mb, maxmemory-policy allkeys-lru |
| 通用 | 限制日志大小 | max-size: 50m, max-file: 3 |
最后建议:如果业务流量稍有增长,2 核 2G 将难以维持稳定。建议在初期就规划好升级路径(如升级到 4 核 4G),或者考虑将 MySQL 迁移到云数据库(RDS),本地仅保留 Redis 和应用代码,以减轻本地磁盘和内存压力。
PHPWP博客