做运维的都遇到过这种工单:业务方说「高峰期连不上」,你登上去看,CPU 不高、内存不紧张、带宽还空着一大截,重启一下应用好像又好了。这种时候十有八九不是资源不够,是连接排队的地方堵了。Linux 上一个监听端口后面排着两条队,很多人干了几年还分不清哪条是哪条,于是就出现了那种经典操作——把 somaxconn 从 128 改到 65535,重启,然后发现啥也没变。
这篇就把这件事讲透:三次握手的三个包分别把连接推进哪个队列、应用写的 backlog 到底管哪一条、系统参数怎么把它悄悄截断、队列满了内核是扔 RST 还是装没看见、以及怎么用几条命令确认到底是不是它。说白了,「连不上」要先分清是握手根本没完成,还是握手完成了没人接——这两种病看着像,治法完全不一样。
先把结论摆在这儿:
tcp_max_syn_backlog 以及内核对 backlog 的换算有关。tcp_abort_on_overflow 决定:为 0 时内核装作没收到最后的 ACK,客户端表现为连接慢;为 1 时直接回 RST,表现为连接被拒。两种症状差别巨大,排查时最容易搞混。先从三次握手说起,把它拆成三个包看,队列的位置就清楚了。
客户端发第一个包 SYN 过来,内核收到后,给这个连接建一条记录,回 SYN+ACK,然后把这条记录放进 SYN 队列(半连接队列)。注意此时站在内核的角度,这个连接还「没成」——它不知道对面是不是真的人,还是个伪造了源地址的空包。所以半连接队列的作用,本质上是给「我发出了 SYN+ACK 但还没收到确认」的连接留个暂存位。
客户端收到 SYN+ACK,回第三个包 ACK。内核收到这个 ACK,确认握手完成,就把这条记录从 SYN 队列里摘出来,挪进 accept 队列(全连接队列)。到这一步,连接在内核里已经是 ESTABLISHED 状态了,但它还不属于任何一个进程——应用必须调用 accept() 把它「取走」,拿到一个文件描述符,才能开始读写数据。
所以两条队列的分界线非常干净:SYN 队列里是「握手没走完」的连接,accept 队列里是「握手走完了但应用还没领走」的连接。前面那条出问题,说明有大量连接卡在半路;后面那条出问题,说明握手都成了、是应用自己接不过来。这两件事的排查方向天差地别,混在一起谈就会越调越乱。
还有个常被忽略的细节:连接在 accept 队列里排队的时候,内核已经把三次握手走完了,客户端那边 connect() 已经成功返回了。所以客户端「连上了但发数据没反应」这种诡异现象,往往就出在这条队列上。
这是面试常考、工程上常错的点。老资料里会说 backlog 是「半连接队列长度」,那是十几年前的内核行为。在现代 Linux 上,listen(sockfd, backlog) 的 backlog 参数决定的是 accept 队列的长度。
半连接队列的长度是另一套算法:它跟 /proc/sys/net/ipv4/tcp_max_syn_backlog 有关,也跟内核对 backlog 值做的换算有关,不同内核版本的具体公式还变过。所以你在应用里把 backlog 调大,影响的主要是全连接那条队;想动半连接队列,得去动 tcp_max_syn_backlog,而且它同样不是唯一的决定因素。
顺带说一句,很多应用框架根本没把 backlog 暴露给你改。比如 Nginx 可以在 listen 指令后面写 backlog=511,但不少 Java、Go、Python 的服务要么用默认值,要么藏在启动参数里。你以为的「默认」和内核实际拿到的值之间,还隔着一道 somaxconn,这就是下一节要讲的。
/proc/sys/net/core/somaxconn 是系统级的 accept 队列长度上限。它跟应用 backlog 的关系是父子关系,而且是「截断」不是「相加」也不是「取平均」:内核拿 min(应用传入的 backlog, somaxconn) 作为最终生效值。
所以那个经典的坑就来了——你把 Nginx 配成 listen 80 backlog=1024,甚至把应用代码里的 backlog 也改成 1024,重启服务,ss -lnt 一看,Send-Q 还是 128。为什么?因为 somaxconn 就是 128,你写 1024 被直接砍掉了。listen ... backlog=511 这种到处能搜到的写法也是一样,那个 511 在默认的 somaxconn 面前照样被拦一道。
改法本身不复杂:
# 临时生效
sysctl -w net.core.somaxconn=4096
# 永久生效
echo 'net.core.somaxconn = 4096' >> /etc/sysctl.conf
sysctl -p
但真正重要的是改完怎么验证它真的生效了。别信配置文件,信命令输出:
sysctl net.core.somaxconn——先看系统值是不是你要的那个。ss -lnt——看目标端口那一行的 Send-Q,它就是这个监听 socket 实际生效的 accept 队列最大长度。改完 somaxconn 必须重启应用进程才会体现在这里,因为 listen() 是在进程启动时调用的,改系统参数不会影响已经跑着的 socket。这一步是很多人漏掉的:sysctl 改完觉得万事大吉,其实老进程还在用老值。net.core.somaxconn 在某些容器运行时下属于不允许在容器内改的那一类,得在宿主机上改,或者走 Pod 的 securityContext 里那套 sysctl 白名单。云主机同理,宿主机层面的限制你不一定碰得到。还有个容易踩的点:systemd 管的进程在启动时如果 somaxconn 还没被 sysctl 应用(比如你把它写在了某个晚于服务启动的脚本里),那进程拿到的还是旧值。所以永久配置一定要写在 /etc/sysctl.conf 或 /etc/sysctl.d/ 下,并确保在网络服务启动之前就应用。
这是全篇最容易把人绕晕的地方,因为同样是 accept 队列满,内核有两种截然不同的处理方式,取决于 /proc/sys/net/ipv4/tcp_abort_on_overflow 这一位。
为 0(多数发行版的默认)时:accept 队列满了,又来了一个完成握手的连接,内核的做法是忽略客户端发来的最后一个 ACK。客户端这边以为握手成功了,其实服务端没认。然后内核会按自己的节奏重传 SYN+ACK,客户端跟着重传 ACK,来回折腾几次,如果这期间应用腾出了队列位置,连接就补上了。表现是什么?连接明显变慢,但最终多半能连上。用户体感是「卡一下」,日志里看不到明确的报错,监控上 connect 耗时 P99 飙了。
为 1 时:内核不装了,直接给客户端回 RST。客户端看到的就是明确的 connection reset / connection refused,报错干净利落,日志里一片红。
这两种表现会让排查走向完全不同的方向。回 RST 的还好查,日志里有明确错误;装没看见的那种最坑,因为从客户端看是「偶尔慢」,从服务端看一切正常,两边各说各话。
SYN 队列满则是另一回事:内核的做法是直接丢弃新来的 SYN,客户端发出 SYN 后等不到 SYN+ACK,于是重传 SYN,重试若干次后超时。客户端看到的是 connect 超时,跟 accept 队列满导致的「慢」完全不是一个感觉。这时候 netstat -s 或 ss -s 里能看到 SYN 丢弃相关的计数在增长——具体字段名在不同内核版本里不一样,别去背字段名,看趋势就行:这个值是不是在故障窗口内持续往上走。
把几个容易混淆的场景摊开看:
| 现象 | 是哪条队列 | 内核行为 | 客户端看到什么 | 观测命令 | 第一反应该做什么 |
|---|---|---|---|---|---|
| 连接明显变慢但最终能连上 | accept 队列 | tcp_abort_on_overflow=0,忽略最后的 ACK,靠重传补上 | connect 耗时长,无明确报错 | ss -lnt 看 Recv-Q | 查应用 accept 速率,别急着调参 |
| 连接直接被拒 / reset | accept 队列 | tcp_abort_on_overflow=1,直接回 RST | 明确的 connection refused / reset | ss -lnt + netstat -s 溢出计数 | 确认溢出计数是否随故障窗口增长 |
| 连接超时,SYN 没响应 | SYN 队列 | 丢弃新来的 SYN | SYN 重传直至超时 | netstat -s / ss -s 丢 SYN 计数 | 判断是否为 SYN flood,看 syncookies |
| 半连接压力大但业务正常 | SYN 队列(cookie 生效) | syncookies=1,用 cookie 完成握手不占队列项 | 正常建连,握手期部分 TCP 选项丢失 | cat /proc/sys/net/ipv4/tcp_syncookies | 确认 cookie 是否被触发,往上查流量来源 |
| 应用报 too many open files | 与队列无关 | fd 达到进程或系统上限 | 服务端报错,连接创建失败 | ulimit -n、/proc/<pid>/limits | 提 LimitNOFILE 与 file-max,别去动队列 |
| 大量 TIME_WAIT 堆积 | 与队列无关 | 主动关闭方进入 TIME_WAIT 并等待 | 一般无感,属正常关闭行为 | ss -ant state time-wait | 查短连接与连接复用,与握手队列分开算 |
讲完原理,落到手上。确认 accept 队列堆积,第一条命令就是 ss -lnt。输出长这样:
State Recv-Q Send-Q Local Address:Port
LISTEN 0 128 0.0.0.0:80
在 LISTEN 状态下,这两列的含义跟 ESTABLISHED 状态下不一样,别按老习惯读:
判据用相对关系说,别去记什么绝对值:Recv-Q 长期贴着 Send-Q,是「应用 accept 不过来」的强信号。偶尔冲上去一下不算,因为突发流量本来就会让它抖;连续采样几十次,大部分时候 Recv-Q 都在 Send-Q 的七八成以上,那基本可以定性了。反过来,如果 Recv-Q 一直是 0 或者个位数,队列根本没堵,你该去别处找原因。
第二条命令是 netstat -s,看溢出和丢 SYN 的计数。重点不是某一次的绝对值,而是故障窗口内它涨不涨。做法很土但有效:故障发生时打一次,隔一分钟再打一次,做差。accept 队列溢出对应的计数在涨,就是实锤;SYN 丢弃的计数在涨,说明问题在半连接那条队。这里提醒一句,不同内核版本对这些计数的命名不一样,别去背字段名,也不要照抄某篇博客里写的名字对着找,认准「增长」这件事就行。
SYN 重传怎么抓?tcpdump -ni eth0 'tcp[tcpflags] & tcp-syn != 0' 把握手包抓下来,看同一个源是不是在短时间内反复发 SYN 却拿不到 SYN+ACK。抓包的价值在于确认到底是服务端没回,还是回了客户端没接——这一刀切下去,是丢包、是队列满、还是中间设备的问题,方向立刻就分开了。
采样的时候有个坑:故障往往只持续几十秒,等你收到告警登上机器,窗口已经过了。所以这几条命令最好提前做成定时采样脚本,每秒一次写文件或上报时序库,出事的时候回看曲线。临时手敲命令抓到一次算运气好,抓不到才是常态。
把上面的动作串成一条线,遇到「高并发连不上」按这个顺序走,能少绕很多弯路:
ss -lnt,看 Recv-Q 与 Send-Q 的相对关系;同时 sysctl net.core.somaxconn 确认生效值。netstat -s 隔一分钟取两次,看溢出计数和丢 SYN 计数分别在不在涨,确定是 accept 队列还是 SYN 队列。这套顺序的核心就一句话:先分清现象,再确认队列,最后才动参数。反过来做的人太多了,一上来就 sysctl 一把梭,改完不知道有没有效,出问题也不知道该回滚哪一个。
这一点我愿意说得重一点:accept 队列堆积,本质上是在告诉你「应用 accept() 或者处理新连接的速度跟不上」。队列只是个缓冲水箱,进水比出水快,水箱迟早要满。你把水箱加高(调大 somaxconn),换来的是水漫出来的时间推迟了,不是进水变慢了。
常见的出水口堵塞有这么几种:
所以正确的顺序是先测 accept 速率,再谈调参。怎么测?最朴素有效的办法是给应用加一层埋点:accept 一次记一次数、记一次耗时,把「每秒 accept 成功数」和「accept 队列当前长度」做成指标上报。有了这两条曲线,你就能回答那个关键问题——我的应用每秒究竟能吃下多少新连接。这个数字才是容量规划的地基,没有它,所有调参都是瞎猜。
测出来之后,优化方向也很清楚:accept 与业务处理分离,accept 线程只管接、接完丢给队列或线程池;批量 accept,一次循环里多接几个而不是一个;把阻塞的慢操作从事件循环里挪走;确认线程池的拒绝策略在高负载下是合理的,别让它悄悄丢活。
连接数上不去的机器,我一般会先看应用侧的 accept 速率再谈内核参数;真要换机器,一万网络自营机柜最快 1 分钟上架,先开一台压一轮再决定,比在老机器上反复调参省事。
/proc/sys/net/ipv4/tcp_syncookies 这个开关,很多发行版默认是 1。它的作用机制值得说清楚:当半连接队列承受压力时,内核改用 cookie 的方式完成握手——把连接的关键信息编码进 SYN+ACK 的序列号里发出去,自己不在这个连接上保留队列项。等客户端回 ACK 的时候,再从序列号里把信息解出来,重建连接。
好处很直接:不占半连接队列项,所以面对伪造源地址的 SYN flood 时,攻击者没法靠灌满队列把你打挂。这是抗 SYN flood 最常用的一个开关,代价也得讲明白:因为握手阶段的信息被压缩进了序列号,部分 TCP 选项在这个阶段无法保留,要等握手完成之后才恢复。对绝大多数业务这个代价可以忽略,但对依赖特定握手期选项协商的场景,就得自己权衡了。
什么时候开?我的看法是:常态开着问题不大,但别把它当成容量方案。它是在队列压力下才触发的应急机制,不是让你放心把队列留小的理由。真正需要警惕的是「syncookies 一直在触发」这件事本身——那说明你一直在被灌 SYN,或者半连接队列长期不够用,两者都该往上查。
更重要的一句:抗 SYN flood 的真实位置在边缘,不在单机的 sysctl 上。攻击流量打到你的机器网卡上,带宽和 CPU 已经在被消耗了,syncookies 只是保证握手逻辑不被打挂,救不了带宽。真要防,得靠上游的防护与清洗能力——流量在进机房之前就该被识别和丢弃。一万网络这边提供 5–20G 免费 DDoS 防护,遇到持续性的 SYN 灌入,正确动作是提工单让上游先扛,而不是自己在这台机器上把参数拧到底。单机硬扛攻击,扛到最后你会发现瓶颈根本不在内核参数上。
高并发场景下,「连不上」这个描述下面藏着好几种病,这里把最容易跟握手队列搞混的几件分开说。
连接建立之后是要占文件描述符的。系统级看 fs.file-max,进程级看 LimitNOFILE(systemd 里的 LimitNOFILE=,或者 ulimit -n 看到的那个)。撞上这道天花板时,报的是 too many open files,日志里写得明明白白。它跟队列满是两种完全不同的症状:队列满的表现是连接慢或被拒,fd 满的表现是进程内部创建连接失败、日志里刷那个错误。别看到「连不上」就去调 somaxconn,先 grep 一下日志里有没有这条。
TIME_WAIT 是连接关闭的时候才有的状态,谁先主动关谁进 TIME_WAIT。它跟握手队列一点关系都没有,排队发生在连接建立阶段,TIME_WAIT 发生在连接结束之后。之所以老被一起提,是因为高并发短连接服务上两者会同时出现,容易让人误以为是因果。
但大量 TIME_WAIT 确实是另一本账:它会占用四元组与内存,短连接密集的服务尤其明显。处理思路也完全不同——查连接复用(长连接、连接池、keepalive),而不是动握手队列的参数。这一篇不展开,你只要记住:看到 TIME_WAIT 多,别往 somaxconn 上想。
挂了负载均衡或者四层转发之后,一次客户端连接其实对应两段独立的握手:客户端到 LB 一段,LB 到后端真实服务器一段。两段的队列是各自独立的,参数也是各自独立的。
排查时最常见的失误是只查一边:客户端报连不上,你去后端机器上一通查,Recv-Q 好好的,于是得出结论「不是队列问题」。殊不知堵在 LB 那一段。反过来也一样。所以只要链路上有转发设备,ss -lnt 和计数必须在每一跳上各跑一遍。
另外,四层转发会改变服务端看到的连接特征——源地址可能变成 LB 的地址(取决于转发模式),连接数也会被汇聚到少数几个后端上。原本分散的连接压力集中起来之后,单机的 accept 队列更容易成为瓶颈。这也是为什么同样是「加了 LB」,有些业务的连接问题反而变多了。
坑一:只改应用 backlog,不管 somaxconn。坑在哪——应用写 1024,系统 128,实际生效 128,改了等于没改,还多花时间排查一遍。怎么避——改之前先 sysctl net.core.somaxconn 看系统值,两个一起改,改完用 ss -lnt 的 Send-Q 确认生效值确实变了。记住 listen() 只在进程启动时调用,改完系统参数必须重启应用。
坑二:把 tcp_abort_on_overflow 当成优化项随手开成 1。坑在哪——开了之后队列满就回 RST,错误是清晰了,但本来能靠重传补上的连接现在直接断了,等于把「慢」变成了「失败」,用户体验可能更差;而且 RST 会把真实原因(应用接不过来)伪装成网络问题,排查反而更难。怎么避——默认保持 0,只有在你明确需要让监控快速感知到溢出、或者客户端有可靠的重试机制时才考虑开 1,并且开之前先想清楚告警怎么接。
坑三:一看到连接数上不去就调队列,不看应用。坑在哪——调大队列只是把拒绝延后,accept 速率没变,高峰期该堵还是堵,只是从「报错」变成「卡死」,用户更难忍受。怎么避——先埋点测出应用每秒能 accept 多少,把这个数字和峰值新建连接速率放在一起比;差距在哪一目了然,先补差距再谈缓冲。
坑四:把 syncookies 当防攻击的终点。坑在哪——它只解决握手逻辑不被打挂,带宽和 CPU 的消耗一分不少,攻击流量照样打进网卡。怎么避——把它当应急兜底,真正的防护放上游;同时监控 syncookies 是否被触发,触发本身就是告警信号,说明有异常流量或者队列容量长期不足。
坑五:容器和云主机里改了参数却不生效,或者只在容器里改。坑在哪——网络命名空间隔离,部分 sysctl 在容器里属于不允许修改的那一类;云主机上宿主机层面的限制你未必碰得到;systemd 服务的启动顺序如果早于 sysctl 应用,进程拿到的还是旧值。怎么避——永久配置统一写进 /etc/sysctl.d/,容器场景走编排平台提供的 sysctl 白名单机制,改完一律用 ss -lnt 的 Send-Q 反查真实生效值,不信配置文件只信命令输出。
没有一个放之四海皆准的数字,但可以给你一个思路。somaxconn 的作用是吸收突发的新建连接,所以它应该跟两个量挂钩:峰值每秒新建连接数,以及应用从队列里取走一个连接需要多久。粗略地说,队列长度要能覆盖「应用卡顿一次」期间涌进来的连接量——比如你应用每秒能吃 5000 个新连接,某次 GC 停顿了 100 毫秒,那这一瞬间会积压大约 500 个,队列长度就得明显大于它才不会溢出。
所以常见的做法是把它设成「峰值新建速率 × 可容忍的排队时长」,再留一倍余量。但更诚实的回答是:如果你需要靠一个很大的 somaxconn 才能扛住,说明应用侧的吞吐本身就不够,这时候该做的是扩容或者优化 accept 路径,而不是继续加队列。另外别忘了,队列加长意味着堆积的连接等待更久,超过客户端超时时间之后,连上了也会被客户端主动断掉,白等一场。
要。这是截断关系的直接推论:生效值是 min(应用 backlog, somaxconn),只抬高一头没用,得两头都抬。所以标准动作是系统参数和应用配置一起改,Nginx 改 listen 后面的 backlog=,其他服务找对应的启动参数或者代码里的 listen 调用。
改完之后还有两步容易漏:一是必须重启应用进程,因为 listen() 是启动时调用的,sysctl 改了不影响已经存在的监听 socket;二是验证,用 ss -lnt 看 Send-Q 那一列是否变成了你期望的值。有的应用压根没暴露 backlog 配置,那就只能改代码或者查框架文档,别以为默认值就合理。最后提醒一句,容器里改完还要确认宿主机那层允许。
大概率你踩在 tcp_abort_on_overflow=0 那种症状上。这个取值下内核不回 RST,只是忽略最后的 ACK,靠重传去补。结果是:服务端没有任何错误日志,连接数、CPU、内存一切正常,监控图上什么都看不出来;而客户端那边是「卡了一下」,用户体感就是慢或者连不上。
根本原因在于你们监控的是资源指标,而队列堆积是个瞬时状态指标,一秒不看就过去了。补的办法有两个方向:一是把 ss -lnt 的 Recv-Q / Send-Q 做成高频采样指标(比如每秒一次)上报,并且对「Recv-Q 持续高于 Send-Q 的某个比例」单独设告警;二是盯 netstat -s 里溢出计数的增量,而不是绝对值——增量在故障窗口内持续为正,就是实锤。另外客户端侧的 connect 耗时 P99/P999 一定要监控,服务端一切正常不代表用户体验正常。
多数发行版默认就是 1,一直开着没什么问题,我的建议也是保持开启。它的触发条件是半连接队列承受压力,正常流量下不会走到 cookie 那条路径,所以你平时感知不到它存在。
代价要说清楚:cookie 机制把连接信息编码进了 SYN+ACK 的序列号,空间有限,因此部分 TCP 选项在握手阶段无法保留,要等握手完成之后才恢复。对绝大多数业务这一点无感,但如果你依赖握手阶段协商的某些选项(比如特定场景下对窗口缩放、时间戳之类的精细控制),就得自己测一遍确认影响。真正需要注意的是另一件事:syncookies 被触发本身就是信号。它说明要么有异常流量在灌,要么半连接队列长期偏紧,两者都值得往上查,而不是开着它就当没事了。
分两层看。云主机(虚拟机):你有完整的 root 和自己的内核,net.core.somaxconn、tcp_max_syn_backlog、tcp_abort_on_overflow 这些一般都能改,写进 /etc/sysctl.d/ 再 sysctl -p 即可,验证方式还是看 ss -lnt 的 Send-Q。但要注意,云平台在网络层可能有自己的限制(比如连接数上限、pps 限制),那一层你改不到,需要提工单确认。
容器:网络命名空间是隔离的,sysctl 分成「允许在容器内改」和「必须在宿主机改」两类,net.core.somaxconn 通常属于后者。正确做法是走编排平台提供的 sysctl 白名单机制(比如 Kubernetes 的 securityContext sysctls),或者在宿主机上统一配置。另外提醒一句,容器的网络栈如果走的是宿主机网络模式,那就完全是宿主机的参数在起作用。总之别在容器里改了半天发现根本没生效,改完一律用命令回查。
短连接服务的特征很清楚:连接建立和关闭的频率都极高,所以两头的账都会变重——建连侧压在握手队列上,关闭侧堆积 TIME_WAIT。我的建议是先分清哪一头先出问题,判断依据很简单:如果报错是连接慢、被拒、超时,看握手队列;如果日志里刷的是地址不够用、或者观察到大量 TIME_WAIT 占着四元组,那是关闭侧的事。
但要说该先管哪一头,我的答案很明确:先管连接复用。短连接的根本问题是「每笔业务都要付一次握手和一次关闭的代价」,握手队列和 TIME_WAIT 都只是这个代价的表现。把轮询改成长连接、把 HTTP 请求走连接池、启用 keepalive,新建连接的速率会断崖式下降,握手队列和 TIME_WAIT 的压力同时缓解。这个收益远比把 somaxconn 从 128 调到 65535 大得多,而且是真正解决问题。队列参数等复用改造做完、有了实测的 accept 速率之后,再按容量去配。
这篇里讲的行为是通用内核行为,但有三件事我必须提醒你不要照抄:不同内核版本的默认值不同,netstat -s 里那些计数的字段名在不同版本里也不一样;不同发行版的默认 sysctl 配置不同,同一个内核跑在不同发行版上,somaxconn 的默认值可能就不一样;云平台的网络层可能另有自己的限制,那不在你的 sysctl 管辖范围内。
查证的路径建议这么走:listen() 的语义看本机 man 2 listen,那是最贴近你当前内核的一份说明;内核参数的含义和取值看内核源码树里的 Documentation/networking/ 与 Documentation/admin-guide/sysctl/net.rst,比任何博客都准;发行版的默认值看它自己的 /etc/sysctl.d/ 下的配置文件,别信「某某版本默认是 X」的二手说法;云平台层面有没有连接数或 pps 的限制,直接提工单问。一万网络提供 7×24 中文工单、平均 5 分钟响应,像「这台机器在高并发下能撑多少新建连接」「网络层有没有额外限制」这类问题,工单问一句比自己猜半天快。
还有一条实操建议:把你现在所有跟连接相关的 sysctl 值存一份基线。sysctl -a | grep -E 'somaxconn|syn_backlog|abort_on_overflow|syncookies|file-max' 的输出存进配置管理或者文档里。等哪天出问题要回滚、或者换了台机器要对比,有这份基线省很多事。参数调多了之后,最容易出的事故是「忘了自己改过什么」。
写到最后,把立场再摆一次:队列是缓冲,不是吞吐。somaxconn 调大,换来的是「被拒绝」变成「排队等待」,用户从明确的报错变成不确定的等待——后者往往更难受。真正能提升并发连接能力的,永远是应用侧每秒能稳定 accept 并处理多少新连接,以及业务层能不能少建点连接。
所以闭环应该是这样的:先埋点测出 accept 速率这个地基数字;再用连接复用把新建连接的绝对量降下来;然后按「峰值速率 × 可容忍排队时长」去配队列长度,作为应对突发的缓冲;最后压一轮复测,确认改完之后峰值时 Recv-Q 不会长期贴着 Send-Q。这四步走完,参数才是有依据的,而不是抄来的。
硬件这边也一样:连接数上不去的机器,很多时候是 CPU 单核性能或者核数撑不住事件循环和协议栈处理,这种时候拧参数拧到天亮也没用,换机器才是解。一万网络深耕 IDC 19 年(成立于 2007 年),深圳南山总部,自营机柜最快 1 分钟上架,先开一台压一轮拿到实测数字,比在老机器上反复调参划算得多。
数据来源:文中为通用内核行为与常见取值逻辑,实际以所用内核版本、发行版与云平台的实际限制为准;具体以签约时最新报价与合同为准。更多服务器租用与运维实践内容可参见 一万网络官网。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品