Agent 架构设计:IP 变化下的寻址方案
深度分析分布式 Agent 系统的核心问题:IP 不稳定导致系统黑暗。强调用身份标识(name/DNS)而非 IP,给出可靠的架构思路。
完整中文译文
你的 Agent 昨天还能正常访问。昨晚,DHCP 租约过期了,容器被重新调度了,或者云平台悄悄重新分配了公网 IP——现在,所有硬编码的 endpoint、所有 webhook URL,以及所有指向它的配置,都指向了一台已经不存在的机器。这是我见过 Agent 集群失联最常见的原因,而且问题从来不在 Agent 本身,而在寻址模型。
解决办法不是更好地追踪 IP,而是不要再把 IP 当作 Agent 的身份。下面才是当 IP 发生变化时,仍要保持 Agent 可访问所必须满足的条件。
为什么 Agent 的地址不应该是它的 IP
IP 地址描述的是一台机器连接在网络的什么位置,并不能说明这台机器是什么。这个区别很重要,因为现代部署模型中的一切设计,都在让“位置”变得不稳定:
笔记本电脑会休眠。当它在新的网络中唤醒时,DHCP 会为它分配一个新地址。
容器会被重新调度。一个新的 pod 意味着一个新的网络 namespace,通常也意味着一个新的 IP。
云平台会重新分配资源。Spot instance 会终止,Elastic IP 会被解绑,部署也会跨 region 迁移。
CGNAT 和运营商网络意味着,你看到的地址甚至不是其他人能够访问的地址。
如果 Agent 的地址就是它的 IP,那么每当 IP 发生变化,Agent 就会变得无法访问——也就是说,最终必然会失联。地址和 IP 必须是两种不同的东西。
IP 变化时,如何让 Agent 保持可访问
要让 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 变化后,你获得的地址依然存在。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。