连接的两级呼吸检测:peertimeout 六十秒与二十分钟的分工 图 1
连接的两级呼吸检测:peertimeout 六十秒与二十分钟的分工 · 图 1

一、连接刚建立就有六十秒的死线

日志里出现”连接建立后没有任何消息”这类记录时,很多人以为对端出问题了。实际上更可能是本机的计时器先到点。Bitcoin Core 对每条对等连接维护两套超时:连接建立后有一段很短的观察期,官方默认值是六十秒——在这段时间内,如果对端连一条消息都没发过,本机就认为这条连接是死的,主动断开。参数名是 -peertimeout,单位秒,参数说明写明最小值为一。

这个六十秒的设计动机很直接:连接在传输层建立成功,不代表对方真的在跑一个健康的比特币节点。半开连接、被防火墙悄悄掐断的会话、资源耗尽后僵住的进程,都会让 TCP 表面存活而应用层沉默。给一个短死线,是让节点能快速放弃假邻居,把有限的连接槽位让给别人。

连接的两级呼吸检测:peertimeout 六十秒与二十分钟的分工 图 2
连接的两级呼吸检测:peertimeout 六十秒与二十分钟的分工 · 图 2

二、活过观察期后换成二十分钟

熬过第一分钟的连接进入另一种节奏。源码里定义了名为 TIMEOUT_INTERVAL 的常量,值为二十分钟,用在两个判定上:上次成功发送超过二十分钟,或者上次收到消息超过二十分钟,都会被判定需要断开,日志分别标记为发送超时与接收超时。也就是说,正常连接每二十分钟内至少要有一次双向互动,否则同样被回收。

两级计时的分工可以这样记:六十秒管”你有没有在跟我说话”,二十分钟管”你是不是还活着”。前者防假连接,后者防长期静默。排障时看日志关键字就能分辨落进了哪一类——“no message in first”开头的是第一类,“sending timeout”或接收超时开头的是第二类。

三、为什么会误伤”看起来正常”的连接

第二类超时最容易冤枉人,因为静默未必是故障。比特币协议设计里有一类消息叫 ping,它存在的意义之一就是”制造一次双向互动”:节点在需要确认连接活性时会发一条带随机数的 ping,对端回 pong,这一来一回刷新了两边的计时器。健康网络里,这种心跳由协议层自动安排,用户感知不到。

但在特定环境里,心跳可能失效。出站流量被透明代理吞掉、路由器长时间 NAT 映射过期、或者对端是一台配置了极端省电策略的设备,都会出现”链路还通、消息已经停摆”的状态。此时两边各自按二十分钟回收连接,日志表现为一堆无规律的断开重连。判断方法是看断开前最后一条消息的时间差:如果恰好接近二十分钟,几乎可以断定是活性超时而非对端作恶。

四、调大它的代价与合理边界

-peertimeout 调大看似能减少掉线,实际是把死线往后推而已——它只影响第一级观察期,二十分钟那级常量不随它变化。真正的”少掉线”来自修复链路本身。对大多数部署,保留六十秒默认值是对整个网络最友好的选择:死线越长,僵尸连接占槽的时间越久,你从网络获得的区块与交易也越可能来自单一来源。

确实需要调的情形有两类。一类是高延迟卫星链路,第一分钟内可能连版本消息都还没交换完,观察期需要适度放宽。另一类是被中间设备限速的环境。两类场景都建议用日志确认”消息确实迟到而不是丢失”后再调,并且调完复看连接数是否稳定,否则只是把症状转移成了延迟。

五、检查自己是不是被对方计时了

反过来,若你的节点总是被邻居断开,也可能是自己没能按时回话。常见原因有三:机器时钟大幅漂移让计时判断失真;同步落后过多导致处理队列拥塞, pong 回复迟到;磁盘或 CPU 饱和让网络线程得不到调度。对应的自查顺序是:先校时,再看同步状态与区块高度差,最后看资源水位。三者都正常却仍频繁被断,才需要怀疑网络路径上的中间设备。把这两级超时理解成”节点为连接设的呼吸检测”,日志里那些冷冰冰的断开原因就有了统一的解释。