第四节:节点发现与网络拓扑
好,咱们今天聊点硬核的——分布式交易所里,节点之间到底是怎么找到彼此的?
你想想看,一个去中心化的交易所,背后可能有几千个节点在跑。没有中心服务器,一个新节点上线,它怎么知道该跟谁打招呼?这就是节点发现要解决的问题。
我个人习惯把这个问题拆成三层来看:
- 底层算法:Kademlia DHT,决定节点怎么组织
- 路由维护:节点怎么更新自己的“通讯录”
- 网络穿透:NAT 环境下的节点怎么互相通信
咱们一层一层剥开。
4.1 Kademlia 分布式哈希表
Kademlia,简称 KAD。说白了,它就是一个分布式的“电话本”。
每个节点有一个 160 位的 ID(通常用 SHA-1 算出来的)。节点之间通过这个 ID 的“距离”来决定谁该认识谁。
注意,这里的距离不是地理距离,而是 XOR 异或距离。
核心公式:distance(A, B) = A.id XOR B.id
这个距离越小,说明两个节点在逻辑上越“近”。
我在项目中遇到过一个问题:刚开始用 KAD 时,以为距离越小越好,结果发现节点全扎堆了。后来才明白,KAD 的精髓在于 “分桶”——每个节点维护多个 k-bucket,每个桶负责一个距离范围。
举个例子:
- 桶 0:距离在 [2^0, 2^1) 之间的节点
- 桶 1:距离在 [2^1, 2^2) 之间的节点
- 桶 i:距离在 [2^i, 2^(i+1)) 之间的节点
每个桶最多放 k 个节点(k 通常取 20)。这样,整个网络就形成了一种 “越近越密,越远越疏” 的拓扑结构。
嗯,这里要注意:桶的数量是固定的,160 个。因为 ID 是 160 位,所以最多 160 个桶。
4.2 节点路由表维护
路由表,就是每个节点本地维护的那个“通讯录”。
它长什么样?我直接给你看伪代码:
// 路由表结构
type RoutingTable struct {
buckets [160]*KBucket // 160个桶
selfID NodeID // 自己的节点ID
}
// 每个桶
type KBucket struct {
nodes []Node // 最多k个节点
lastSeen time.Time // 最后一次刷新时间
}
路由表的维护,说白了就三件事:
- 节点加入:新节点上线,先找几个种子节点,然后通过 FIND_NODE 请求逐步填充自己的路由表。
- 节点更新:收到任何消息,都要检查对应桶,如果节点已存在就刷新时间戳,如果桶没满就加入。
- 节点淘汰:桶满了怎么办?我曾经踩过这个坑——直接丢弃新节点。结果导致网络分裂。
避坑指南:我曾经在测试网里发现,桶满了之后直接丢弃新节点,会导致老节点下线后,新节点永远无法加入。正确的做法是:
- 先 ping 一下桶里最久没联系的节点
- 如果它活着,就丢弃新节点
- 如果它死了,就替换掉它
还有一个细节:刷新机制。每个桶如果超过 1 小时没更新,就要主动发起一次刷新。我一般设置成 30 分钟,因为交易所的节点变动比较频繁。
4.3 NAT 穿透与中继节点
好,现在问题来了。大部分节点都在 NAT 后面——家庭网络、云服务器、甚至手机热点。它们没有公网 IP,怎么互相通信?
这就是 NAT 穿透要解决的问题。
常见的穿透方式有三种:
| 方式 | 原理 | 成功率 | 我的评价 |
|---|---|---|---|
| UDP 打洞 | 双方同时向对方公网地址发 UDP 包 | 60%-70% | 简单,但依赖 NAT 类型 |
| STUN/TURN | 通过服务器协调 | 90%+ | 稳定,但需要服务器 |
| 中继节点 | 通过第三方节点转发 | 100% | 最可靠,但延迟高 |
我个人习惯的做法是:优先尝试 UDP 打洞,如果失败就切换到中继。
中继节点的部署,其实很简单。它就是一个有公网 IP 的节点,专门负责转发消息。但要注意:
- 中继节点不要参与交易撮合,只做转发
- 每个中继节点限制连接数,比如 500 个
- 中继节点之间要互相备份,防止单点故障
小技巧:我在部署中继节点时,会在每个节点上跑一个健康检查脚本,每 5 秒检测一次。如果某个中继节点挂了,其他节点会自动把它的客户端分配到备用节点上。
4.4 整体拓扑结构
说了这么多,咱们用一张图来总结一下整个网络拓扑:
从这张图你能看到:
- 中继节点在最上层,它们之间互相备份
- 普通节点通过 Kademlia 协议互相连接,形成一个 P2P 网络
- NAT 节点无法直接连入 P2P 网络,需要通过中继节点转发
说白了,整个网络就是 “中继保底,KAD 为主” 的混合架构。
嗯,最后说一句:节点发现这块,看起来简单,但坑特别多。我当年第一次搭建测试网时,就因为路由表刷新频率设得太低,导致节点分裂成两个孤岛,交易对不上了。后来我加了一个心跳机制,每 10 秒互相 ping 一次,才稳定下来。
所以,别小看节点发现。它是整个分布式交易所的骨架。骨架歪了,上面再好的业务逻辑也白搭。
公众号:蓝海资料掘金营,微信deep3321