4. 操作系统参数调优

聊完硬件和中间件,咱们得把目光放到操作系统层面。密钥服务最终跑在Linux上,内核参数就像地基,地基不稳,上层再优化也白搭。我个人习惯是先看三样东西:文件描述符、TCP参数、内核VMM相关参数。这三样调好了,密钥服务的吞吐和延迟基本就稳了。

核心思路:操作系统调优不是把参数往大了设,而是找到业务瓶颈与资源上限的平衡点。密钥服务多是短连接、小报文、高并发,所以TCP的TIME_WAIT、端口范围、backlog队列这些是重灾区。

操作系统参数调优知识体系 内核参数调优 文件描述符 ulimit -n file-max nr_open TCP 参数 tcp_tw_reuse / recyle tcp_fin_timeout ip_local_port_range 内核与内存 vm.swappiness net.core.somaxconn kernel.sem / shmmax 调优原则:先确认业务瓶颈(连接数?端口耗尽?TIME_WAIT积压?),再有针对性地调整

4.1 文件描述符——别让进程“张不开嘴”

密钥服务每处理一个请求,基本上就要打开一个socket。如果文件描述符上限设得太低,进程会在高并发时直接报错:“Too many open files”。我曾经在生产环境遇到过这个错误,排查了半天才发现是ulimit没配,那叫一个尴尬。

调优主要关注三个层面:

  • 用户级限制:ulimit -n,建议设为 65535 或更高。通过 /etc/security/limits.conf 设置。
  • 系统级限制:/proc/sys/fs/file-max,决定内核能分配的最大文件句柄数。一般按 1000 * 并发连接数预估。
  • 最大可打开数:/proc/sys/fs/nr_open,通常和 file-max 保持一致或略大。
参数 位置 建议值 备注
ulimit -n /etc/security/limits.conf 65535 / 1048576 需同时设置 soft 和 hard
fs.file-max /proc/sys/fs/file-max 512000 ~ 1048576 按实际并发估算
fs.nr_open /proc/sys/fs/nr_open ≥ file-max 防止部分进程拉高全局上限

避坑提醒:我之前碰到一个案例,ulimit 配了 65535,但进程里用 systemd 启动,systemd 的服务文件里没配 LimitNOFILE,结果实际限制还是默认的 1024。所以记得检查 systemd 的 LimitNOFILE=65535。

设置方法示例:

# limits.conf 添加
* soft nofile 65535
* hard nofile 65535

# sysctl 永久配置
echo "fs.file-max = 1048576" >> /etc/sysctl.conf
sysctl -p

4.2 TCP 参数——让连接跑得更顺

密钥服务大多使用短连接,每次请求都会建连、断连。如果不调优,TIME_WAIT 会堆成山,端口会耗尽,新连接连不上。我经历过一次线上故障,客户端报 “Cannot assign requested address”,一看端口全被 TIME_WAIT 占满了。嗯,从那以后我就把 TCP 调优当成默认动作了。

以下是我最常用的几个参数:

参数 作用 参考值 说明
net.ipv4.tcp_tw_reuse 允许重用 TIME_WAIT socket 1 配合 tcp_timestamps 使用,很安全
net.ipv4.tcp_tw_recycle 快速回收 TIME_WAIT 0(强烈建议关闭) NAT 环境下会导致连接异常,别开
net.ipv4.tcp_fin_timeout FIN_WAIT2 超时时间 15 ~ 30 缩短等待时间,释放资源
net.ipv4.ip_local_port_range 客户端可用端口范围 1024 65000 扩大范围,防止端口耗尽
net.core.somaxconn TCP 全连接队列长度 1024 ~ 4096 配合应用程序 backlog 参数
net.ipv4.tcp_max_syn_backlog 半连接队列长度 1024 ~ 4096 抗 SYN 洪水有用

经验值:我的密钥服务集群一般配成:tcp_tw_reuse=1、tcp_fin_timeout=15、ip_local_port_range=1024 65535、somaxconn=4096。配合上负载均衡的 keepalive,连接复用率能到 70% 以上。

配置命令:

cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
EOF
sysctl -p

这里要特别提醒一句:tcp_tw_recycle 在新版内核(4.12+)已经被移除,旧版如果开了,在 NAT 环境下非常坑。我有一个客户在云上启用了这个参数,结果客户端请求偶尔超时,抓包发现随机丢 SYN。查了好几天,关掉就好了。所以一定别碰它。

4.3 内核与内存参数——稳住底层

操作系统调优里容易被忽略的是内存和信号量相关参数。密钥服务通常使用异步 I/O 或事件驱动模型,内存分配策略和进程间通信(比如使用共享内存做缓存)都会受影响。

我一般会检查这几个:

  • vm.swappiness:控制内核使用 swap 的倾向。密钥服务对延迟敏感,建议设为 0 或 1,尽量用物理内存。
  • vm.dirty_ratio / dirty_background_ratio:控制脏页回写。写密集型场景适当调低,减少突然卡顿。
  • kernel.sem:信号量参数,如果用了消息队列或共享内存,要按并发量调大。
  • kernel.shmmax / shmall:共享内存段最大尺寸,如果密钥服务用共享内存缓存密钥,需要调大。
参数 含义 建议值
vm.swappiness swap 倾向(0~100) 0 或 1(延迟敏感场景)
vm.dirty_ratio 脏页占内存百分比上限 20 ~ 30
vm.dirty_background_ratio 后台脏页回收阈值 5 ~ 10
kernel.sem 信号量数组(4个值) 250 32000 100 128
kernel.shmmax 单共享内存段最大值 物理内存的一半或更多
kernel.shmall 共享内存总页数 物理内存页数

调试技巧:如果想验证配置是否生效,可以用 cat /proc/sys/net/ipv4/tcp_tw_reuse 查看实时值。另外 ss -s 可以快速看到 TIME_WAIT 数量,调优前后一对比就知道效果了。

对了,调完所有参数后别忘了 sysctl -p 重新加载。我习惯写一个调优脚本,在服务器初始化时自动执行,避免漏配。下面是个完整示例:

# 密钥服务 OS 级一键调优脚本
cat > /etc/sysctl.d/99-kms.conf << 'EOF'
# 文件描述符
fs.file-max = 1048576

# TCP 连接复用
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535

# 队列深度
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096

# 内存 & swap
vm.swappiness = 0
vm.dirty_ratio = 20
vm.dirty_background_ratio = 5

# 共享内存 & 信号量
kernel.shmmax = 68719476736   # 64GB
kernel.shmall = 16777216      # 64GB 的 4K 页数
kernel.sem = 250 32000 100 128
EOF

sysctl --system

# 用户级文件描述符限制
echo '* soft nofile 65535'  >> /etc/security/limits.conf
echo '* hard nofile 65535'  >> /etc/security/limits.conf

到此,操作系统层面的三个核心调优方向都覆盖到了。记住一个原则:先看业务指标(连接数、QPS、延迟),再针对瓶颈做参数调整。别盲目照搬网上所谓的“最佳配置”,每个服务的特点不一样。我吃过这个亏,拿别人数据库的优化参数塞给密钥服务,结果性能反而降了。