bitcoind 的线程名册:msghand、net、scheduler 各在打哪行日志 图 1
bitcoind 的线程名册:msghand、net、scheduler 各在打哪行日志 · 图 1

打开比特币核心的 -logthreadnames 后,debug.log 每行前面多出一个方括号标签。要读懂这行日志”是 bitcoind 的哪个线程打的”,得先知道 v31.0 里到底有哪些线程、各自负责什么。本文按源码里的线程创建点列一份名册,并给出”日志在动但某功能失联”这类故障的对应排法。

名册:显式命名的常驻线程

v31 的源码给线程命名有两类写法,最终都落到每行日志的方括号标签上。按创建位置整理常驻名册:net 是 socket 处理线程,所有对端连接的收发就绪都过它;msghand 是消息处理线程,验证并处理每条入站消息、驱动区块与交易下载,绝大多数 NET 与 MEMPOOL 日志产自这里;dnsseed 只在需要用 DNS 种子获取地址时存在;addcon 维护”已添加”来源的连接,opencon 负责排队中的出站连接尝试;scheduler 是定时任务线程,节点里所有延时任务——地址重公告、feefilter 节拍、连接重试、限速配额窗口重置——都挂在它的队列上;http 是 libevent 事件分发线程,RPC 与 REST 的收发在它的循环里调度;torcontrol 在配置洋葱隐藏服务时出现;mapport 在 NAT 端口映射(NAT-PMP/PCP)开启时出现;privbcast 服务于私有广播;i2paccept 在配置了 I2P 监听时负责接受入站连接;initload 承担后台预取与加载;多进程 IPC 模式下还有 capnp-loop;关机的收尾路径会把当前线程改名为 shutoff,日志里看到它就是停机流程在走。多数名字出现在统一的追踪包装函数调用点——建线程时把名字字符串交给同一个入口,因此这份清单可以从一个符号顺藤摸瓜查全。

bitcoind 的线程名册:msghand、net、scheduler 各在打哪行日志 图 2
bitcoind 的线程名册:msghand、net、scheduler 各在打哪行日志 · 图 2

两类线程名与索引线程

还有一批线程通过进程级命名接口注册,同样出现在标签里:并行脚本校验的工作线程按 scriptch.0scriptch.1 这样的编号命名,数量由 -par 决定(默认按核心数自适应),批量验证区块与交易的签名校验都压在它们身上;GUI 路径下另有 qt 前缀的一组线程名。开启索引后,后台同步线程直接以索引自身命名——txindex 的线程标签就是 txindex,coinstatsindex 与区块过滤索引同理(过滤索引带类型前缀)。看到线程名为 unknown 的行不必恐慌——日志实现取的线程名是空串时直接填 unknown,它只是说明那个执行流没做命名注册,结合日志分类与消息内容定位归属即可。

用名册排障

几组高频对应关系:连接数不涨但 msghand 一直活跃,看 addcon/opencon 是否卡在 DNS 解析或地址供给,再配合 getnettotalsgetpeerinfo;RPC 请求全排队但 http 在动,多半是工作线程被慢调用占住,用 getrpcinfo 看活跃请求队列点名;节点整体停止响应而 scheduler 一行都没有,怀疑调度线程阻塞在锁上——它停摆时地址公告、feefilter、重连会一起失联,症状非常有辨识度;只有 shutoff 在打日志,说明进程已经在退出路径上,等它把各模块收尾完即可;验证索引卡进度时,索引线程标签与数据目录下 indexes 里的子目录同名(如 txindex),日志与磁盘状态可以直接对照。日志里时间戳之后的方括号排序规则见上一篇文章的拼装顺序一节。

两个提醒

第一,线程名是调试装饰不是稳定接口:小版本重构可能改名、合并或新增线程,跨版本对比日志样本时以当版源码为准;同一进程内并发多钱包时,钱包任务也可能借用已有线程执行,名册不是并发的精确画像。第二,标签只回答”谁写的”,不回答”写得对不对”,定位事实仍要回到日志正文与状态 RPC;把线程名和 getinfogetrpcinfogetnettotals 这类快照 RPC 搭配用,先定位子系统再下结论,比翻整页日志快得多。以上名册与默认值依据 Bitcoin Core v31.0 源码整理,不构成投资建议。