一台比特币核心节点拨出去和收进来连接之后,其实一直在被两只秒表盯着:一只是可配置的六十秒试用期,另一只是写死在源码里的二十分钟固定线。很多排障帖把这两种断开混为一谈,本文按 v31.0 源码把两条线各自量的是什么讲清楚,并给出参数调整的正确姿势。
六十秒试用期的判定逻辑
节点与对端建立 TCP 连接后,并不能立刻用”有没有流量”来判断对方是不是坏邻居——慢链路、代理握手、Tor 建立电路都可能需要时间。因此比特币核心给每条新连接设了一个观察窗口:参数 -peertimeout 控制这个窗口的长度,默认 60 秒,允许的最小值是 1 秒。它是一个调试级参数,只出现在扩展帮助(-help-debug)里,普通用户手册不会提及。
窗口期内的行为在源码 src/net.cpp 的 ShouldRunInactivityChecks 函数里写得非常直白:从连接建立时刻算起,只要还没跨过这条线,节点对这条连接完全不跑任何不活跃检查。也就是说,前六十秒里哪怕双方一条消息都没交换,节点也不会动手断开——这段时间是留给慢速环境的宽容期。
跨过窗口线之后,检查才真正上岗:如果一条连接到现在为止从未收到过对端任何消息,或者从未向对端发出过任何消息,就会被判死刑并断开,日志里会留下 “socket no message in first 60 seconds” 这样一行,附带这条连接是否收过、发过的说明。想读懂这一行,需要把 debug 日志的网络分类打开。
二十分钟那条线不归它管
很多人以为把 -peertimeout 调大就能保住一切空闲连接,这是个误会。窗口期结束后的持续健康检查用的是另一个常量:src/net.h 中定义的 TIMEOUT_INTERVAL,固定二十分钟。一条已经正常握手过的连接,如果最后一次发包或最后一条收包距今超过二十分钟,仍会被分别以 “socket sending timeout” 或接收超时的名义断开,这与 -peertimeout 设成多大毫无关系。
换句话说,-peertimeout 量的是”新生儿有没有活过第一个小时”,二十分钟线量的是”成年人多久没露面算失联”。源码里还有一条测试注释顺带交代了前者的另一种用途:在用 mocktime 做时间穿越测试时,把 -peertimeout=999999999 设大,防止虚拟时间推进时节点把邻居全部踢光。
它与三个近邻参数的分界
比特币节点里带”超时”字样的参数不止一个,混淆的代价是调错旋钮:-timeout 管的是操作系统层连接建立的等待(默认五秒),连不上那一刻就生效,与本参数的窗口完全不同轨;RPC 侧的等待归 -rpcservertimeout 等参数管;而同步链时”区块下载卡住”的判定又是另一套内部计时。本文的参数只回答一个问题:连接建立之后、进入基于收发的断开判定之前,给多久缓冲。
实操建议
第一,家用宽带加 Tor 或走远端代理的节点,如果日志频繁出现 “socket no message in first 60 seconds”,把 -peertimeout 适度抬大(例如 120)是合理诊断动作,但先排查是不是防火墙丢包更值得做。第二,不要为了保留一条”偶尔才有消息”的专线而指望调大此参数——空闲判定在窗口之后由二十分钟固定线接管,调它没用。第三,此参数改动不影响已经建立的正常连接,也不会改变入站连接驱逐、地址管理等任何一层逻辑。
怎么确认这台节点当前的观察窗
-peertimeout 的生效值不会出现在 RPC 返回值里,核对方法就朴素得多:看进程启动参数、看配置文件里有没有遗留行、或者做一发对照实验——把窗口临时设大重启,观察那台可疑对端的存活时长是否随之变化。改参数属于重启生效的动作,动手前先把停机流程走干净,避免在同步中途硬拔造成日志噪音掩盖真实问题。
风险提示:本文讨论比特币核心节点的网络参数机制与排障语义,不涉及任何资产价格,也不构成投资建议;所有行为描述以 v31.0 源码为准,旧版本与此后版本的默认值和实现可能不同,配置前请以你实际运行的版本文档为准。
参考来源
- 比特币核心 v31.0 源码 src/net.cpp(GitHub):https://github.com/bitcoin/bitcoin/blob/v31.0/src/net.cpp
- 比特币核心 v31.0 源码 src/net.h(GitHub):https://github.com/bitcoin/bitcoin/blob/v31.0/src/net.h
- 比特币核心 v31.0 源码 src/init.cpp(GitHub):https://github.com/bitcoin/bitcoin/blob/v31.0/src/init.cpp
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。