网络编程最大的敌人不是网络,是你的乐观

🔑 关键词:网络编程,TCP,容错,连接池,超时

📖 摘要:作者通过一次线上排障经历,讨论网络编程中真正困难的地方不是协议本身,而是程序员对网络可靠性的错误假设。提出“乐观派程序员”的概念,并给出一些务实的建议。

我曾花了两天两夜查一个线上故障。 我们的服务响应偶尔会慢三秒,但看起来完全随机。 最后抓包才发现,服务端会关闭空闲连接,那个连接池里的客户端浑然不知,等请求一发出,服务端直接回了RST。 客户端HTTP库憨憨地重试一次,第二次才成功。 所以那慢三秒不是网络慢,是我们自己给自己设的套。

图片

从那天起我开始意识到,我们写网络代码时总是不自觉地做三个假设:网络很快、网络很稳、连接永远存在。 本地函数调用失败是代码bug,可网络调用失败那是日常。 上学时老师教我怎么写socket,怎么连服务器,却从没告诉我怎么面对失败。 我甚至见过有的人把超时设成30秒,重试设成无限次,好像只要自己参数调得够大,网络就会变得温柔。

图片

后来我踩了更多坑,发现真正的陷阱往往来自TCP协议本身的坏脾气。 比如Nagle算法和延迟ACK凑在一起,会出现一个活活卡住的小包,哪怕数据中心零丢包,也能给你搞出40毫秒延迟。 还有TIME_WAIT端口耗尽,连接池只增不减,微服务之间像八爪鱼一样互相揪着。 这些问题不在你代码里,在内核里,在协议栈的每一个妥协里。 你要是只看应用层,永远想不通为什么。

图片

所以我现在学乖了。每个外部调用必须设超时,超时后要有一个降级方案;重试要有上限,最好加上退避;连接没连上要快速失败,而不是耗着。 说白了,你得在心态上承认一件事:你控制不了整条链路,你只能在边界上做正确的事。 网络编程从来不是写代码,是跟真实世界谈判。 它让我谦卑,也让我上瘾,因为每一场故障都是这个世界在教我做人,而我终于学会了听。

图片

🏷️ 标签: