sysctl 是什么
sysctl 是 Linux 内核暴露给用户的运行时参数配置接口。简单理解就是:你不需要修改内核代码、不需要重启机器、甚至不需要重启服务,就能动态调整操作系统内核的行为。你可能听过某些优化需要 "改内核参数",这些参数大多数就是通过 sysctl 来查看和设置的。
我第一次接触 sysctl 是刚工作那会儿,公司服务器出现大量 TIME_WAIT 连接,导致新连接建不起来。老同事跑了一行命令,问题瞬间缓解。那一幕让我对这个工具产生了深刻的印象。后来自己开始负责线上环境,sysctl 几乎成了每台服务器初始化脚本的标配。
查看当前内核参数
先用最基础的操作,看看 sysctl 怎么用:
# 查看所有内核参数,数量很大(通常有几百到上千个),配合 less 分页
sysctl -a | less
# 查看某个具体参数的值
sysctl net.ipv4.tcp_tw_reuse
# 用通配符模糊查找,比如所有和 tcp 相关的参数
sysctl -a | grep tcp
sysctl -a 会把所有可配置的内核参数全部列出来,不同的内核版本和加载的模块不同,数量从几百到上千不等。你在里面可以看到网络、内存、文件系统、安全等各个子系统的参数。
查看单个参数的时候需要注意路径格式:sysctl 使用点号(.)分隔层级,对应 /proc/sys/ 目录下的文件路径。比如 net.ipv4.tcp_tw_reuse 对应的是 /proc/sys/net/ipv4/tcp_tw_reuse。你可以用 cat 直接读这个文件,结果和 sysctl 是一样的:
# sysctl 和直接读 /proc/sys/ 等效
cat /proc/sys/net/ipv4/tcp_tw_reuse
理解这个对应关系很重要。你在网上看到的教程如果让你 echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse,效果等同于 sysctl -w net.ipv4.tcp_tw_reuse=1。
临时修改参数
临时改参数是 sysctl 最主要的用法场景。改完立即生效,不需要重启任何东西:
# 临时开启 tcp_tw_reuse,允许将 TIME_WAIT 状态的 socket 用于新连接
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
# 修改 swappiness 控制内存换出策略(值越小越倾向于不换出匿名内存)
sudo sysctl -w vm.swappiness=10
# 增加系统级别的文件打开数上限
sudo sysctl -w fs.file-max=1000000
# 修改网络缓冲区大小
sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.wmem_max=16777216
这里说几个我实战中反复用到的参数:
vm.swappiness:控制内核在回收内存时是倾向于回收 page cache 还是 swap out 匿名内存页。取值范围 0-100,默认通常是 60。对于数据库服务器(MySQL、PostgreSQL),我一般调到 10 甚至 1,让程序尽量留在内存里。对于普通的 Web 服务器,保持默认就行,不用刻意调低。
net.ipv4.tcp_tw_reuse:允许重用 TIME_WAIT 状态的连接。注意这个参数在容器环境中(Docker/Kubernetes)以及新的内核版本(5.x 以上)中,部分行为有变化。在生产环境改之前一定要做测试。
fs.file-max:系统级别的文件句柄上限。和后面要讲的 ulimit 不同,这个是全局上限,ulimit 是进程级别的限制。两个都要配,只配一个不够。
⚠️ 安全提醒:临时修改只会生效到下次重启。如果你跑了一堆 sysctl -w 然后重启了机器,所有修改都会丢失。不要以为改了就永远生效了。另一个风险是改错了参数可能导致系统行为异常,比如把 vm.swappiness 改成 100 会让系统频繁交换内存,性能急剧下降。
永久配置:写入 /etc/sysctl.conf
要永久生效,需要写到配置文件里。最常见的做法是修改 /etc/sysctl.conf 或者在 /etc/sysctl.d/ 下创建自己的配置文件:
# 编辑主配置文件(或者创建自己的文件)
sudo vi /etc/sysctl.conf
在文件末尾添加参数配置,每行一个:
# 开启 TIME_WAIT socket 重用
net.ipv4.tcp_tw_reuse = 1
# 降低 swappiness,减少内存交换
vm.swappiness = 10
# 增加系统文件句柄上限
fs.file-max = 1000000
# 增大 TCP 读写缓冲区范围
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 开启反向路径过滤(防止 IP 欺骗)
net.ipv4.conf.all.rp_filter = 1
# 启用 TCP keepalive,检测死连接
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 8
配置写完后,用 sysctl -p 重新加载配置:
# 从 /etc/sysctl.conf 重新加载配置
sudo sysctl -p
# 也可以指定从某个文件加载
sudo sysctl -p /etc/sysctl.d/99-custom.conf
-p 不会重启服务或系统,它只是把配置文件里的值逐个应用到当前运行的内核。如果有参数写错了,sysctl 会报错,不会影响其他参数。
一个比较好实践是:不要全往 /etc/sysctl.conf 里写。建议在 /etc/sysctl.d/ 下创建自己的配置文件,比如 90-custom.conf,按功能分类。这样以后排查配置的时候一目了然,升级系统也不会被覆盖。
常用内核参数详解
这里列几个生产环境中我经常配置的参数,每个都附上使用场景:
# 开启 SYN flood 保护,防止半连接攻击的经典配置
sysctl -w net.ipv4.tcp_syncookies=1
# 缩短 TIME_WAIT 的超时时间(默认60秒)
# 注意:这个值改小了会影响极端情况下的连接可靠性
sysctl -w net.ipv4.tcp_fin_timeout=15
# 增大连接队列长度,适合高并发短连接的场景
sysctl -w net.core.somaxconn=65535
# 设置内存中允许挂起的最大 TCP 连接数
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
# 允许 ip_local_port_range 覆盖更多的临时端口
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
我遇到过一个经典场景:API 网关服务器每秒钟产生大量短连接,TIME_WAIT 堆积到几万个,可用端口耗尽。当时的优化组合就是 tcp_tw_reuse + tcp_fin_timeout=15 + 调大 ip_local_port_range,配合 somaxconn 和 tcp_max_syn_backlog 扛住连接风暴。这不万能,但在绝大多数场景下足够有效。
内核参数生效确认
改完参数后怎么确认真的生效了?有几个方法:
# 方法一:直接 sysctl 查看
sysctl net.ipv4.tcp_tw_reuse
# 方法二:通过 sysctl 查看多个参数,确认持久化配置正确加载
sysctl -a | grep -E 'tcp_tw_reuse|swappiness|file-max'
# 方法三:直接读 proc 文件系统
cat /proc/sys/net/ipv4/tcp_tw_reuse
# 方法四:查看当前生效的所有 sysctl 配置,和配置文件做对比
sudo sysctl -a > /tmp/sysctl_current.txt
diff /tmp/sysctl_current.txt <(sysctl --system 2>/dev/null)
如果 sysctl -p 执行时报错,通常是配置文件里写错了参数名或者写错了值。比如 vm.swappiness=10 你写成了 vm.swappiness=10g,sysctl 会直接报 "invalid argument"。修正后重新执行 sysctl -p 就行。
一个典型场景:初始化新服务器的 sysctl 配置
这里分享一个我个人的服务器初始化模板,你可以在新机器上直接参考:
# 第一步:保存原始配置,方便回滚
sudo sysctl -a > /tmp/sysctl_backup_$(date +%Y%m%d).txt
# 第二步:创建自定义配置文件
sudo tee /etc/sysctl.d/99-server-tuning.conf << 'EOF'
# 网络优化
net.core.somaxconn = 65535
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_syncookies = 1
net.ipv4.ip_local_port_range = 1024 65535
# 内存优化
vm.swappiness = 10
vm.vfs_cache_pressure = 50
# 文件句柄
fs.file-max = 1000000
# 内核安全
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_sack = 1
EOF
# 第三步:加载配置并验证
sudo sysctl --system
sysctl net.core.somaxconn vm.swappiness fs.file-max
sysctl --system 这个命令比较新(systemd 系统上支持),它会按顺序加载所有配置文件:先 /etc/sysctl.d/*.conf,再 /etc/sysctl.conf。建议用这个代替 -p,因为 -p 只加载你指定的文件。
sysctl 常见坑
1. 改了值不生效,可能是因为参数被你改错了名字。比如很多人把 net.ipv4.tcp_tw_reuse 记成 net.ipv4.tcp_tw_recycle(后者在内核 4.12 之后已经被移除了)。
2. /etc/sysctl.d/ 下的文件是按字典序加载的,后加载的会覆盖先加载的。所以如果你在 90-custom.conf 里配了某个值,又在 99-other.conf 里配了同一个值,后者生效。
3. 云服务器(AWS、阿里云、腾讯云)的内核可能打了自定义补丁,某些参数的行为可能和标准内核不同。改之前先测一下。
总结
sysctl 是你深入 Linux 内核配置的入口。不需要重启就能调整内核行为,这在性能调优和故障应急中价值极大。建议你把常用的参数配成自己的 "初始化脚本",每台新服务器都跑一遍。好的内核参数配置能避免很多不必要的线上问题。