在做高并发系统(Nginx / Redis / MySQL / Elasticsearch)时,很多人都会整理一套 sysctl 参数,比如:
fs.file-max = 2097152
net.core.somaxconn = 65535
vm.swappiness = 0
vm.max_map_count = 262144
...
👉 但一到 Docker 环境,问题就来了:
❓这些参数到底该写在容器里,还是只能改宿主机?
如果你也踩过这些坑,这篇文章可以帮你彻底理清。
🧠 一句话结论(先记住这个)
| 类型 | 能否在 Docker 设置 |
|---|---|
vm.* | ❌ 只能宿主机 |
fs.* | ❌ 基本宿主机 |
net.* | ⚠️ 部分可以 |
conntrack | ❌ 宿主机 |
👉 核心原则:
- 影响全局资源的 → 宿主机
- 网络命名空间相关 → 容器可尝试
🧱 为什么 Docker 不能随便改 sysctl?
Docker 不是虚拟机,它是共享宿主机内核的。
👉 所以 sysctl 参数分两类:
✅ 可命名空间隔离(namespaced)
-
每个容器可以不同
-
例如:
net.*- 一部分
kernel.*
❌ 全局参数(global)
-
改了就是改整个宿主机
-
例如:
vm.*fs.file-max
👉 Docker 官方限制:
只能设置 namespaced sysctl
🔥 你的这套参数,正确分类应该是这样
✅ 一、必须在宿主机设置的(重点)
fs.file-max = 2097152
fs.nr_open = 2097152
vm.swappiness = 0
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.overcommit_memory = 0
vm.max_map_count = 262144
fs.aio-max-nr = 1048576
net.nf_conntrack_max = 262144
📌 为什么?
| 参数 | 原因 |
|---|---|
vm.* | 控制内存策略(全局) |
fs.file-max | 全机文件句柄上限 |
conntrack_max | NAT/连接跟踪全局表 |
max_map_count | ES 必须,宿主机级 |
👉 举个典型坑:
Elasticsearch 报错:
max virtual memory areas vm.max_map_count [65530] is too low
你在容器里改?👉 没用
👉 必须宿主机改
⚠️ 二、可以放 Docker 的(部分 net.*)
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.core.netdev_max_backlog = 5000
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.netfilter.nf_conntrack_tcp_timeout_established = 300
👉 这些大概率可以写进 Docker:
docker run 写法
docker run -d \
--sysctl net.core.somaxconn=65535 \
--sysctl net.ipv4.tcp_max_syn_backlog=8192 \
nginx
docker-compose 写法(推荐)
services:
nginx:
image: nginx
sysctls:
net.core.somaxconn: 65535
net.ipv4.tcp_max_syn_backlog: 8192
net.ipv4.ip_local_port_range: "1024 65535"
⚠️ 但这里有 3 个大坑(很多人不知道)
❗坑 1:不是所有 net.* 都能用
👉 是否生效取决于:
- 内核版本
- Docker runtime
- 网络模式
👉 结论:
能不能用,以容器是否报错为准
❗坑 2:用了 --network=host 会失效
👉 如果你这样跑:
docker run --network=host ...
那么:
❌ net.* sysctl 基本不能用
👉 因为你直接用了宿主机网络栈
❗坑 3:sysctl ≠ 性能一定提升
举个经典例子:
net.core.somaxconn = 65535
👉 但你 Nginx:
listen backlog=511;
👉 那你调再高也没用 😅
🧩 高并发系统正确调优姿势(重点)
🧱 宿主机层
# /etc/sysctl.conf
vm.swappiness=0
vm.max_map_count=262144
fs.file-max=2097152
net.nf_conntrack_max=262144
sysctl -p
🐳 Docker 层
sysctls:
net.core.somaxconn: 65535
net.ipv4.tcp_max_syn_backlog: 8192
⚙️ 应用层(很多人忽略)
Nginx
worker_connections 65535;
listen backlog=65535;
Redis
tcp-backlog 65535
MySQL
open_files_limit=65535
🧵 进程级(ulimit)
docker run --ulimit nofile=1048576:1048576 ...
🧠 一张图总结(核心记住)
性能调优 = 宿主机 + Docker + 应用 + ulimit
不是只改 sysctl!
🚀 最后总结(面试级回答)
👉 如果面试官问:
Docker 里 sysctl 怎么调?
你可以这样答:
- Docker 只能设置 namespaced sysctl(主要是 net.*)
- vm.* / fs.* / conntrack 必须在宿主机配置
- 使用 docker-compose sysctls 配置容器级参数
- host 网络模式下 net.* 无法设置
- sysctl 必须配合 ulimit + 应用配置一起调优
👉 这一套说出来,基本是高级工程师水平。