导读:本文讲述了在Linux系统有两个参数,几十年没有改过。通过表象看本质,它说明了什么?
数据库 crash 重启了,业务却迟迟恢复不了。
监控报警一片红,业务方打来电话,DBA 确认数据库早就正常了。那问题出在哪?
答案藏在一个 Linux 内核参数里:tcp_retries2=15。这意味着 TCP 发现对端不可达后,要重传 15 次才放弃连接,总耗时约 924 秒——将近 16 分钟。数据库虽然恢复了,但旧连接上的数据还在往黑洞里灌,应用要等 16 分钟才能感知到连接已死。
把这个参数从 15 改成 5,恢复时间从 957 秒降到 20 秒。
一个参数,差了 50 倍。
——
Linux 下有两个内核参数,默认值从诞生至今几十年几乎没变过:
1) tcp_keepalive_time,默认 7200 秒,连接空闲 2 小时后才发第一个探活包。
2) tcp_retries2,默认 15 次,重传约 924 秒后才放弃连接。
这些值在二三十年前的网络环境下是合理的——带宽低、延迟高、链路不稳定。但在今天的数据中心内网里,延迟低至亚毫秒级,这些保守的默认值反而成了隐患。
——
先说 tcp_keepalive_time。
长连接需要保活,这个参数的逻辑很简单:连接空闲 7200 秒后发探活包。但客户端和服务端之间不是直连的,中间横着一堆设备——防火墙、LVS 负载均衡、NAT 网关。这些设备为了节省资源,对闲置连接都有超时释放策略:
LVS/IPVS 默认 900 秒释放闲置连接。防火墙通常 900 到 1800 秒。云 NAT 网关通常 300 到 900 秒。
看出问题了吗?中间设备最短 300 秒就释放连接,而 keepalive 默认要等 7200 秒才探活。等探活包发出来的时候,连接早就被丢掉了。
以 LVS 为例。LVS 的 IPVS 模块看到一个连接 900 秒没流量,就从连接跟踪表中删除。但客户端和服务端对此一无所知,TCP 状态仍然是 ESTABLISHED。当客户端在第 901 秒发请求时,包到达 LVS 后已经没有转发规则了——直接丢弃或 Reset。
最坑的是报错时机。错误不会在连接被释放时触发,而是下次使用连接时才暴露。可能连接 15 分钟前就死了,但直到业务发请求才报错。而且报错千奇百怪——Connection Reset、Broken Pipe、SocketException、Read Timeout——表面看各种不同的现象,根源只有一个:连接被中间设备静默释放了,两端都不知道。
解决方案:把 tcp_keepalive_time 调到中间设备超时的最小值以下。我们设置为 300 秒,配合探测间隔 30 秒、探测 5 次,确保在任何中间设备释放连接之前探活包就到了。问题彻底消失。
——
再说 tcp_retries2。
开头的故障就是典型案例。这个参数影响所有 TCP 连接场景:依赖的微服务做了高可用切换,调用方 16 分钟才感知到。K8s Pod 被强摘后旧连接全部超时。云服务变配升级,客户端长时间报错。
更隐蔽的是,这 16 分钟内连接池里的坏连接不释放,新请求拿到坏连接就失败,连接池耗尽,整个服务雪崩。
把 tcp_retries2 从 15 改到 5 到 7,重传超时从 16 分钟缩短到 20 到 60 秒。业务更快拿到错误、更快释放旧连接、更快建立新连接。
——
你可能会说:不就是改两个 sysctl 参数吗?有什么了不起的?
问题在于,识别问题需要深厚的基础功底。
业务方看到的是"服务响应慢"、"偶尔超时"、"连接报错",表象背后可能有一百种原因。如果你不理解 TCP 重传机制、不知道 LVS 闲置超时策略、不了解 keepalive 工作原理,你根本不会想到去看这两个参数。
同样的道理。TCP 偶发精确 3 秒超时——不是应用 bug,是 SYN 丢包后的重传间隔 1 秒加 2 秒。大量 CLOSE_WAIT 堆积——不是网络问题,是应用没有调用 close()。LVS 后端 20 倍负载不均——不是配置错误,是调度算法中 active 连接权重是 inactive 的 256 倍。TCP 连接数据互串——不是灵异事件,是 tcp_tw_recycle 在 NAT 环境下回收了不该回收的 TIME_WAIT。
每一个千奇百怪的故障背后,都有一个清晰的技术根因。你对底层原理理解得越深,你在故障面前就越从容。
——
更关键的是,这两个参数改完是全局生效的。
不需要每个业务团队去改代码、调超时、学 TCP 保活。基础技术做一次,上面跑的几百个服务都受益。越底层的优化,影响面越大。这就是基础技术的杠杆效应。
有人会说业务开发就应该自己设超时、管好连接池。这话没错但不现实。业务开发的核心任务是实现业务逻辑,他们不可能也不应该深入到 TCP 重传机制来理解每个参数。如果要求每个业务开发都成为网络专家,那基础技术团队存在的意义是什么?
基础技术的使命,就是让业务开发不需要关心这些。
——
我喜欢用一个比喻来解释。
业务开发就像在大海上的船里踩缝纫机。他们的目标是把布缝好,不是去对抗风浪。基础技术要做的是:无论外面惊涛骇浪,保证船行驶平稳。如果船摇摇晃晃,他们踩缝纫机就会经常扎到手指。如果你能把震荡隔离掉,他们踩缝纫机自然就顺利了。
最好的基础技术,是让上层无感知。
——
最后一个问题:为什么内核开发者几十年都没改这两个值?
不是因为他们不够厉害,而是因为他们缺少一样东西——真实的业务场景。
内核开发者面对通用场景,7200 秒的 keepalive 确保探活包不冲击网络,15 次重传确保糟糕环境下尽量保持连接。从通用性角度没有错。但放到有 LVS、有防火墙、有 NAT、有几百个微服务的生产环境中,问题就暴露了。
这告诉我们两件事。
第一,业务场景对工程师至关重要。 再厉害的技术脱离业务场景就失去方向。
第二,基础技术的价值在于连接理论与实践。 既懂协议栈原理,又了解生产环境拓扑,还能理解业务痛点,在三者之间找到最优解。
——
作为技术人,不能每天追新概念、新框架、新架构,而忽视脚下的基础。你的技术价值首先是为业务保驾护航。
两个参数的调整,让几百个服务的可用性提升一个量级。这不比追一个新潮的技术名词有价值得多吗?
越是基础的东西,越有力量。因为它是地基,地基稳了,上面才能盖高楼。
作者:Plategg
网址:
https://plantegg.github.io
本篇文章为 @ 场长 创作并授权 21CTO 发布,未经许可,请勿转载。
内容授权事宜请您联系 webmaster@21cto.com或关注 21CTO 微信公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。
请扫描二维码,使用微信支付哦。