ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux内核参数调优:从sysctl到文件描述符,避开常见坑

Linux内核参数调优:从sysctl到文件描述符,避开常见坑 简介文档收录了Linux系统调优中关于网络、文件系统与内核的关键参数说明适合系统运维、网络工程师及服务器管理人员作为日常排查与调优的速查手册。内容围绕/proc/sys/net目录下的TCP/IP参数展开逐一说明rmem_max、wmem_max如何影响接收和发送缓冲区大小tcp_timestamps如何增加包头开销tcp_sack如何优化丢包重传tcp_window_scaling如何突破64K窗口限制同时给出写入rc.local或sysctl.conf实现永久生效的配置示例便于直接实践。除网络参数外还补充了super-max、super-nr、acct、ctrl-alt-del等文件系统与内核配置项的含义帮助读者建立完整的调优视图。文档强调调优需结合具体业务与硬件环境不适当的修改可能导致性能下降甚至系统不稳定建议先进行基准测试并持续监控系统行为。资源包仅含1个docx文件大小18KB内容集中精炼已有312人学习下载适合需要快速掌握Linux网络性能调优关键项的工程师使用。1. 从一份调优参数清单说起为什么直接照抄会翻车接手一台 Linux 服务器网上随手搜一份「Linux 操作系统调优参数」清单十分钟就能把 sysctl.conf 改得满满当当。可这类清单最大的问题是把「默认策略」当成「最优策略」同一份 net.ipv4 参数照搬到数据库服务器可能把 TCP 连接复用开过头同一份 vm.swappiness 在容器宿主机和桌面发行版上的表现也完全两样。调优参数要解决的不是「让 Linux 变快」而是让内核的内存回收、文件句柄、TCP 连接和进程调度策略贴合你实际的负载形态。下面按三类作用域拆开讲——内核运行参数、用户态资源限制、内核启动参数把每个参数改的是什么、影响谁、怎么验证说清楚照着落地不至于翻车踩了坑也知道去哪查。2. 调优参数的生效机制先分清三类作用域再动手动手改参数之前最容易被忽略的是「这个参数归谁管」。同一个「改文件描述符上限」的需求至少有三条完全不同的路径写/etc/sysctl.conf只动内核全局值改/etc/security/limits.conf只影响登录会话改 systemd 服务单元里的LimitNOFILE才管得住被 systemd 拉起的守护进程。很多人把这几类混在一个文档里抄结果就是改了一堆文件服务重启后原形毕露。2.1 用 sysctl 读写 /proc/sys查看、验证、回滚的三条命令/proc/sys是内核运行参数的「黑匣子」sysctl 本身只是读写它的工具。你写进sysctl.conf的每一行最终都要落到/proc/sys下面某个文件上。这一步不重视就会出现改完配置、进程也重启了但cat /proc/sys/...一看还是老值的情况。# 查看单项参数确认当前值 sysctl vm.swappiness # 临时写入立即生效但不持久重启自动还原 sysctl -w vm.swappiness20 # 从配置文件重载全部参数适合改完 /etc/sysctl.d 后统一生效 sysctl -p /etc/sysctl.confsysctl -w是最适合做验证的命令它只改当前运行的内核不写任何文件改错了重启就是后悔药。真正要持久化得把参数写进配置文件再sysctl -p重载。有些发行版用sysctl --system一次性加载/etc/sysctl.conf和/etc/sysctl.d/下的所有文件兼容性最好的还是sysctl -p指定文件路径。改完之后立刻cat /proc/sys/vm/swappiness看一眼确认不是配置文件改了、运行值没跟上。2.2 三个配置载体的差别sysctl.conf、/etc/sysctl.d/ 与 tuned持久化配置也有三种常见落地位置很多人没有区分它们的加载时机导致参数被「后加载」的值覆盖。载体加载时机适用场景/etc/sysctl.conf开机早期sysctl -p手动触发传统发行版兜底少量全局参数/etc/sysctl.d/*.confsystemd-sysctl 启动时按文件名顺序加载按业务模块拆分用99-前缀做自定义tuned profiletuned-adm运行时动态应用可能周期性覆盖按性能模式吞吐/延迟切换基准/etc/sysctl.d/是现在的主流做法文件名按字典序生效用99-custom.conf这样的命名可以保证自己的配置最后加载。tuned 的 profile 里也有 sysctl 段它会在启动完成之后把 profile 里的参数重新应用一遍所以你写在/etc/sysctl.conf里的值可能被 tuned 无声覆盖。这一点放到第 5 章详谈但选载体时就要想清楚如果这台机器装了 tuned业务参数最好直接写进自定义 profile而不是跟 tuned 抢同一个键。2.3 用户态资源限制与内核参数是两套路径ulimit 与 systemd 的边界内核参数管的是「系统全局策略」用户态限制管的是「单个进程能拿多少资源」两者不在同一层。ulimit -n只管当前 shell 启动的子进程systemd 服务读的是 service 单元里的LimitNOFILE完全不走 shell 的路径。这就解释了为什么 ssh 上去ulimit -n 65535之后手动跑 Java 进程没问题一旦用 systemd 重启服务又打回原形。嵌入式 Linux 上更典型很多精简发行版没有/etc/security/limits.conf也没有完整的 PAM 链只能靠启动脚本里先ulimit -n再 exec 主程序。还有一类参数连/proc/sys都不在属于内核启动参数比如isolcpus、transparent_hugepage这类要在 GRUB 的 CMDLINE 或者嵌入式设备的 bootargs 里改必须重启才生效。这类参数混在 sysctl 文档里是最坑的抄进去之后sysctl -p直接报错因为键不存在。2.4 动手之前先做基线快照没有基线就谈不上调优。任何参数改动之前先把自己这台机器「改之前长什么样」留下来后面不管是验证效果还是回滚都靠这份快照说话。mkdir -p /root/tuning_baseline sysctl -a /root/tuning_baseline/sysctl.$(date %F).log ulimit -a /root/tuning_baseline/ulimit.$(date %F).log cat /proc/meminfo /root/tuning_baseline/meminfo.$(date %F).log cat /proc/net/softnet_stat /root/tuning_baseline/softnet_stat.$(date %F).log快照不只是「留个底」。/proc/meminfo在低负载和高负载下差异很大所以快照时要顺手记录当前业务状态/proc/net/softnet_stat看的是网卡软中断丢包网络调优前后对比这个文件最有说服力。等出了问题diff两份快照能少吵很多架。3. 内存、文件系统与文件描述符资源参数vm 与 fs 的取舍内存类是调优参数里抄的人最多、理解的人最少的部分。很多人一上来就把 swappiness 改成 0理由是「不用 swap 就是快」结果内存一紧张业务进程先被 OOM killer 干掉。这组参数的正确用法不是「调到一个值就完事」而是先搞清楚每种资源在内核里的回收路径。3.1 vm.swappiness先理解它在回收路径中的位置vm.swappiness默认是 60范围 0 到 100它控制的是内存压力下内核更倾向回收匿名页还是页缓存。值为 60 意味着匿名页和页缓存的回收权重接近值调低表示「尽量保留匿名页优先回收文件缓存」不是「关掉 swap」。数据库服务器常见做法是调到 10 到 20让内存中不活跃的进程页有机会换出同时保留足够 page cache 给数据文件完全没有 swap 的容器宿主机会有人调到 0 或接近 0但那要配合严格的 cgroup 内存上限否则 OOM 会来得毫无缓冲。sysctl 层面改起来很简单一行配置# /etc/sysctl.d/99-custom.conf vm.swappiness 15注意发行版差异部分内核和 cgroup v2 环境里容器读到的 swappiness 是memory.swappiness跟宿主全局值不是一回事。改完用sysctl vm.swappiness确认别只看配置文件。3.2 过度分配与 mmap 上限overcommit_memory、overcommit_ratio、max_map_countvm.overcommit_memory控制内核是否允许「超出物理内存加 swap 的分配申请」。默认 0 是启发式允许合理的过度分配设为 1 表示总是允许Redis 官方就建议设 1避免 BGSAVE fork 子进程时由于内存分配策略导致失败。部分数据库会设成 2表示禁止超过overcommit_ratio计算出的额度这种模式对大内存程序很危险启动时 malloc 可能直接失败。vm.max_map_count是另一个高频问题点默认 65530Elasticsearch 这类大量用 mmap 的 Java 应用几乎必报max virtual memory areas vm.max_map_count [65530] is too low。常见的调整是 262144。这个键在低内存嵌入式设备上要小心调大意味着每个进程可以映射更多内存区域内核管理开销会涨。参数常见默认值常见调整值适用场景vm.swappiness6010-20数据库、缓存型服务vm.overcommit_memory01Redis、2部分数据库视应用内存模型而定vm.max_map_count65530262144Elasticsearch / Java 大量 mmap3.3 文件句柄与 inotifyfs.file-max、fs.nr_open、fs.inotify.*文件描述符相关的调优参数最容易被人搞混层级。fs.file-max是系统级文件描述符总量的上限内核会按内存估算一个默认值fs.nr_open是单个进程能打开的硬上限默认通常 1048576而ulimit -n是用户态对这个进程的进一步约束。三者关系是进程实际能打开的 fd 数min(ulimit 软/硬限制, fs.nr_open)并且所有进程累计不能超过 fs.file-max。fs.inotify.max_user_watches是另一个隐蔽坑。用 inotify 做配置热加载、文件同步的服务文件一多就开始刷inotify watch limit reached。这个值很多发行版默认只有 8192同步几万个文件的目录基本必炸。常见做法调到 524288但占用的内存会随 watch 数量线性上涨嵌入式设备上要按文件量估算。挂载参数也属于这一层但不在 sysctl 文件里。noatime/nodiratime能减少读文件时的元数据写操作对高并发只读场景的提升最直接现代内核默认的relatime已经是折中方案不用刻意全关。barrier这类数据一致性参数则相反追求极端性能关掉 barrier 的代价是掉电时文件系统可能损坏不建议在生产环境碰。3.4 OOM 行为参数panic_on_oom 与 oom_score_adj内存类参数调到最后要回答一个问题内存真不够的时候谁先死。vm.panic_on_oom设为 1 会让内核在内存耗尽时直接 panic 而不是杀进程适合集群环境里「宁可重启机器也不要跑在半残状态」的场景单机业务服务一般保持 0让 OOM killer 按 oom_score 挑进程。oom_score_adj是给关键进程「保命」的手段在 systemd 服务里对应OOMScoreAdjust。把 MySQL、Nginx 这样的核心进程设成负值比如OOMScoreAdjust-500能明显降低它被选中的概率但要清醒这只是提高存活概率内存真的耗尽时谁也拦不住。配合 swap 和 swappiness 一起调才是完整的内存回收方案。4. 网络与高并发调优参数net.core 与 net.ipv4 的配合网络类调优参数是网上文档最多、也最容易被抄坏的部分。很多新人对着一篇「Linux 常用命令大全运维」风格的旧文档把tcp_tw_recycle打开结果 NAT 环境下的用户随机掉线。网络参数的改法讲究「链路各段配合」queue 缓冲、TCP 生命周期、连接追踪是一套组合拳单独调一个键很难见效。4.1 net.core.*socket 缓冲区与接受队列先给够net.core.somaxconn是 listen 状态 socket 的 accept 队列上限新内核默认 4096老内核可能只有 128。高并发接入层要看两个值一个是内核的 somaxconn另一个是应用自己 listen backlog。Nginx 的listen 8080 backlog4096、JavaServerSocket(int port, int backlog)两者要同步调大否则光调内核、应用还是排队 128。net.core.netdev_max_backlog是网卡收包到协议栈之间的队列长度默认 1000突发流量下丢包可以先看这个。确认方法是压测时查/proc/net/softnet_statdropped 列持续增长就需要调大。rmem_max和wmem_max是 socket 收发缓冲上限默认 212992 左右大流量场景可以调到 16777216但这是「上限」不是「每连接分配」内核按需增长别担心调大了内存立刻爆。参数常见默认值典型调整值说明net.core.somaxconn4096新65535需与应用的 backlog 同步net.core.netdev_max_backlog100016384突发流量丢包时调大net.core.rmem_max / wmem_max21299216777216大连接缓冲按内存评估4.2 net.ipv4.*TCP 连接生命周期上的四个关键点TCP 连接的生命周期从 SYN 队列开始到 TIME_WAIT 结束每一段都有对应参数。net.ipv4.tcp_max_syn_backlog是半连接队列长度配合tcp_syncookies1能在 SYN 洪泛时保命。大量短连接服务最头疼的是 TIME_WAIT 堆积这里要分清两个参数tcp_tw_reuse可以复用处于 TIME_WAIT 的连接但依赖时间戳选项NAT 环境谨慎tcp_tw_recycle在 Linux 4.12 之后已经移除旧文档里还在抄别再用。短连接为主的 Web 接入层常用一组配置我的习惯是先调 fin_timeout 和端口范围而不是急着开 reuse# /etc/sysctl.d/99-custom.conf net.ipv4.tcp_fin_timeout 15 net.ipv4.tcp_tw_reuse 1 net.ipv4.ip_local_port_range 1024 65000 net.ipv4.tcp_keepalive_time 600tcp_fin_timeout从默认 60 秒降到 15 秒TIME_WAIT 数量会明显下降比开 reuse 温和。ip_local_port_range默认 32768 到 60999出站连接多的服务经常端口不够用扩到 1024 起是常见操作但别贪心范围太大可能挤占其他服务。tcp_keepalive_time默认 7200 秒如果前面有负载均衡或云安全组2 小时不活跃连接可能被中间设备先掐掉调到 600 秒左右更保险。注意一组参数要整体压测改完用ss -s看 TIME_WAIT 总量。4.3 连接追踪nf_conntrack 的容量与超时装了 firewalld、iptables 或 nftables 的机器每次新建连接都要经过连接追踪net.netfilter.nf_conntrack_max决定这张表能放多少条目。常见发行版默认 65536 到 262144看着不小但nf_conntrack_tcp_timeout_established默认 432000 秒也就是 5 天大量短连接会把表项堆满。表满之后现象非常典型dmesg 刷nf_conntrack: table full, dropping packet新建连接卡死老连接正常。解决思路是开源节流调大nf_conntrack_max同时把 established 超时降到 1800 到 3600 秒。注意 conntrack 条目要占内存保守按 500 字节一条估算100 万条就是 500MB调大之前先看内存余量。另外确认/proc/sys/net/netfilter/nf_conntrack_count和 max 的比值常年超过 80% 就要处理。4.4 网络调优验证ss、netstat、sar 怎么配合参数改完不能说「感觉快了」要读到三个层面的证据。ss -s看总体 socket 统计和 TIME_WAIT 数量ss -lnt看 listen 队列Recv-Q 表示当前 accept 队列积压Send-Q 是 backlog 上限Recv-Q 长期接近 Send-Q 说明队列不够。netstat -s | grep -E overflow|drop|retrans看协议栈丢包和重传。sar -n DEV 1 5看网卡 pps 和带宽sar -n TCP,ETCP看连接建立和重置速率。这些 linux 常用命令组合起来能定位是队列丢包还是 TCP 层重传再回头调对应参数。5. 调优参数常见坑与排查五条真实翻车记录这章是给所有「照着文档抄完结果更糟」的人准备的。五个场景我都实际见过有的甚至在同一台机器上反复出现每条按现象、原因、解决的顺序写方便你直接对照。5.1 改了 /etc/sysctl.conf重启后参数被 tuned 覆盖现象sysctl -p当时生效reboot 之后net.core.somaxconn又回到旧值。 原因装了 tuned 的机器上tuned-adm的 profile 在系统启动后重新应用了自己的 sysctl 配置把/etc/sysctl.conf里的值覆盖了。 解决先用tuned-adm active确认当前 profile把业务参数写进 profile 对应的/etc/tuned/profile/sysctl文件或者干脆停用 tuned只保留你自己的 sysctl 配置。不要两个地方都写同一个键你永远不知道谁后加载。5.2 swappiness 设为 0 后内存不足时 OOM 来得更快现象swap 几乎没用但业务进程频繁被 OOM killer 干掉。 原因swappiness0 是「尽量不换出匿名页」不是「禁止 swap」。内存压力增大时内核优先回收 page cache文件缓存被大量清理匿名页却在持续增长最后直接触发 OOM。有 swap 的话内核可以先换出部分不活跃进程的页面给紧急回收留缓冲。 解决不要设 0。数据库类服务设 10 到 20配合保留至少 2GB swap容器宿主靠 cgroup 限制内存并监控available memory而不是看free的第三行。5.3 老手册里的 tcp_tw_recycle 已经不可用现象抄了网上的旧文档把net.ipv4.tcp_tw_recycle1打开运行一段时间后 NAT 用户随机连接超时、SSH 掉线。 原因tcp_tw_recycle依赖 TCP 时间戳来自 NAT 后面不同主机的连接时间戳不同步内核会把仍在使用的连接误判为过期直接丢包。Linux 4.12 起该参数被移除但大量旧文档和面试题还在提它。 解决先sysctl net.ipv4.tcp_tw_recycle确认当前内核是否支持不支持就把配置删掉。TIME_WAIT 多时改用tcp_tw_reuse加调小tcp_fin_timeout再配合扩大ip_local_port_rangeNAT/负载均衡环境对 tw_reuse 也要先在测试环境压一波再上。5.4 ulimit -n 显示了 65535进程仍然报 too many open files现象shell 里ulimit -n输出 65535但服务进程一压测就报too many open files文件句柄卡在 1024 附近。 原因你改的是登录会话的 soft limitsystemd 启动的服务继承的是服务自身的LimitNOFILE默认经常只有 1024不读/etc/security/limits.conf。 解决用systemctl show service -p LimitNOFILE确认服务的实际限制在 service 单元里加LimitNOFILE1048576然后systemctl daemon-reload再重启服务。同时检查fs.file-max和fs.nr_open都高于这个值。容器里还要看容器运行时层面的 ulimit改宿主不一定透传。5.5 conntrack 表满导致新建连接卡死现象业务上老连接正常、新连接超时dmesg 里刷nf_conntrack: table full, dropping packet。 原因nf_conntrack_max不够且 established 超时过长短连接表项堆积到上限新连接无法创建跟踪条目。 解决调大net.netfilter.nf_conntrack_max把net.netfilter.nf_conntrack_tcp_timeout_established降到 1800 到 3600监控 nf_conntrack_count 和 max 的比值。如果业务确认不需要状态防火墙也可以评估用 raw 表对相关流量做 NOTRACK从源头减少追踪条目这一步要结合防火墙策略设计别为了调优牺牲安全。5.6 回滚三件事恢复、确认、留档任何参数改动都必须能回滚。我的习惯是三条改动写进配置文件再sysctl -p而不是只执行sysctl -w回滚时把对应行从配置文件删除重载后再diff基线和当前值容器环境要确认/proc/sys是宿主视图别把容器内的只读挂载当成可调对象。留档是最后一道保险谁改的、改了什么、为什么改写进 git 或工单避免一个月后参数被人「顺手」还原排障两天才发现是配置漂移。6. 用压测和基线对比来验收调优效果调优参数改完最后一步不是看配置是跑一轮跟改之前完全相同的负载用数据确认参数真的起了作用而不是「感觉系统变快了」的玄学。我的常用做法是每台机器留一个固定的验收脚本Web 服务用 wrk 或 ab 跑 5 到 10 分钟数据库用 sysbench 的 oltp 模型网络瓶颈用 iperf3。压测记录三个指标——吞吐量、P99 延迟、sys 态 CPU 占比再加上压测过程中的错误数和重传数。对比基线快照里的同名数据提升超过 5% 才算有效低于这个值说明瓶颈不在你调的参数上别自我感动。验证通过之后参数要固化到配置管理里而不是留在手改的/etc/sysctl.d/文件中。Ansible 有专门的 sysctl 模块把参数写进 playbook用 git 管理变更历史容器镜像则在构建阶段写入镜像内的 sysctl 配置确保每次发布环境一致。参数文件命名按业务区分比如99-mysql.conf、99-gateway.conf别把所有键塞进一个99-custom.conf否则后续排障连哪个业务段都不敢动。我在这块吃过大亏早年调完一台生产数据库没有留档一个月后参数被同事用发行版默认配置覆盖线上查询超时排了两天最后diff基线才知道是配置漂移。从那以后我给自己定了个死规矩——参数改动先进 git 再落机基线快照保留至少三个月的轮转。这个方向本身不难难的是每一次改动都可审计、可回滚、可对比。希望这篇把三类作用域和常见坑讲清楚之后你能少走点弯路调出经得起压测的参数而不是经不起重启的参数。本文还有配套的精品资源点击获取
返回列表