深度分析分布式 Agent 系统的核心问题:IP 不稳定导致系统黑暗。强调用身份标识(name/DNS)而非 IP,给出可靠的架构思路。
你的 Agent 昨天还能正常访问。昨晚,DHCP 租约过期了,容器被重新调度了,或者云平台悄悄重新分配了公网 IP——现在,所有硬编码的 endpoint、所有 webhook URL,以及所有指向它的配置,都指向了一台已经不存在的机器。这是我见过 Agent 集群失联最常见的原因,而且问题从来不在 Agent 本身,而在寻址模型。
解决办法不是更好地追踪 IP,而是不要再把 IP 当作 Agent 的身份。下面才是当 IP 发生变化时,仍要保持 Agent 可访问所必须满足的条件。
IP 地址描述的是一台机器连接在网络的什么位置,并不能说明这台机器是什么。这个区别很重要,因为现代部署模型中的一切设计,都在让“位置”变得不稳定:
笔记本电脑会休眠。当它在新的网络中唤醒时,DHCP 会为它分配一个新地址。
容器会被重新调度。一个新的 pod 意味着一个新的网络 namespace,通常也意味着一个新的 IP。
云平台会重新分配资源。Spot instance 会终止,Elastic IP 会被解绑,部署也会跨 region 迁移。
CGNAT 和运营商网络意味着,你看到的地址甚至不是其他人能够访问的地址。
如果 Agent 的地址就是它的 IP,那么每当 IP 发生变化,Agent 就会变得无法访问——也就是说,最终必然会失联。地址和 IP 必须是两种不同的东西。
要让 Agent 在 IP 频繁变化时仍然可访问,必须同时满足四个条件。我发现,评估一个解决方案时,逐一检查这四点非常有用,而不能只看第一点:
身份与位置相互分离。 其他 Agent 用来找到你的地址,不能随着你的 IP 改变而变化。它应该是名称或 ID,而不是路由器分配的一串数字。
映射关系能够自动更新。 当 IP 变化时,Agent 必须能够自动向某个 registry 或 nameserver 公布自己的新位置。如果还需要人工修改配置或 DNS 记录,那么在相关人员醒来处理之前,Agent 都会处于不可用状态。
可访问性不依赖公网 IP。 在 NAT 背后——例如家庭网络、办公室防火墙或云端 egress 环境——根本不存在入站路径。真正让一个地址可以从任何地方访问的,是 hole-punching 和 relay fallback,而不是只能从 Agent 最初所在的数据中心访问它。
传输层能够承受地址变化。 一旦 endpoint IP 在连接过程中发生变化,TCP 会立即断开,socket 也随之失效。基于 UDP、并在 userspace 实现可靠性的传输方式,可以在地址变化后继续维持 session,因为这里的“连接”属于 overlay,而不是绑定在某个 IP 上的 kernel socket。
大多数关于“保持可访问”的建议,都止步于第一个条件。于是得到的系统只能工作到网络真正发生变化的那一刻。
要为 Agent 提供一个比 IP 更持久的地址,真正可行的方案有三种。它们并不能互相替代,因为各自面向的是不同问题。
Dynamic DNS。 运行一个 client,在 IP 变化时更新 DNS 记录。它很简单,对于拥有公网 IP、需要稳定 hostname 的服务器来说也确实有效。但它无法满足第三和第四个条件:在 NAT 背后,没有任何可供 DNS 记录指向的入站地址;而且 DNS 本质上只是映射关系的缓存——TTL、resolver cache 和传播延迟,都可能导致 IP 变化很久以后,peer 仍然解析到旧地址。DDNS 用在博客上没什么问题,但对于必须立即保持可访问的 Agent 来说,它太脆弱了。
Overlay VPN(Tailscale、ZeroTier)。 这些方案正确处理了身份问题,NAT traversal 的效果也确实很好——机器在网络变化后仍能保留自己的名称,这是真正解决了同一个问题。它们主要面向机器和人类用户的 VPN 使用场景:加入一个 tailnet,获得一个地址,然后建立连接。它们很擅长完成自己的目标。
Pilot Protocol 这类 Agent-native overlay。 如果需要保持可访问的是 Agent,而不是笔记本电脑,我会选择这一类方案。Pilot Protocol 会为每个 Agent 提供一个永久的 virtual address,即使 Agent 重启、IP 变化或跨云迁移,这个地址也不会改变。daemon 会持续向 registry 更新 Agent 当前所在的位置,因此 peer 总能把同一个地址解析到它的当前位置。传输层使用加密 UDP tunnel(X25519 key exchange 加 AES-GCM),并在 userspace 实现可靠性;NAT traversal 则使用 STUN 和 hole-punching,并提供 relay fallback。因此,家庭路由器背后的 Agent,与云端 VPC 中的 Agent 一样可以访问。它是开源项目(使用 Go 编写,仅依赖 standard library),目前网络中已有超过 24.3 万个 Agent 和用户。
坦诚地说:如果你只是需要为拥有公网 IP 的服务器提供一个 hostname,DDNS 就很合适。Overlay VPN 适合人类和机器的 VPN 访问。而 Pilot 面向的场景是:其他 Agent 需要在任意网络中找到并访问你的 Agent,同时无需你手动修改 DNS 或开放端口。
具体来说,“地址比 IP 更持久”意味着,那些过去需要你时刻照看的环节,从此不再是你的问题:
curl -fsSL https://pilotprotocol.network/install.sh | sh
daemon 只需注册一次,Agent 就会获得自己的地址。当网络发生变化时——无论是笔记本电脑从休眠中唤醒、容器被重新调度,还是云平台重新分配了 IP——daemon 都会向 rendezvous registry 重新公布新位置。其他任何东西都不需要改变:
pilotctl set-hostname order-processor # once
# ...days later, on a different network, different IP...
pilotctl send-message order-processor --data 'status?'
第二条命令可以从任何地方正常执行,因为 order-processor 从来都不是那个 IP。无需更新 DNS 记录,无需购买 static IP,也无需重新配置 port forwarding。这个地址是一个名称,网络会把它解析到 Agent 当前所在的位置——这就是整个设计的核心。
要让 Agent 在 IP 变化后仍然保持可访问,就必须从设计阶段解决这个问题:将身份与位置解耦,让网络自动重新公布位置,而不是依赖人工操作;确保没有公网 IP 时仍然能够访问;并选择不会把连接绑定到单一地址的传输方式。用这四个条件检查任何声称能“保持可访问”的解决方案,你就能在故障真正发生之前看清它的失效模式,而不是等到出问题之后才发现。
如果你正在构建需要被其他 Agent 发现的 Agent,Pilot Protocol 关于 Agent addressing 的文档会更详细地介绍 registry、address model 和 NAT traversal。执行上面的安装命令,大约一分钟就能建立一个 node——而且在下一次 IP 变化后,你获得的地址依然存在。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。