Skip to content

失败处理

Megascale 的 bootstrap 有三种结构性失败模式,每一种都会产生独特的日志特征和不同的传播路径。下面的行为是二进制实际实现的行为,由反汇编和字符串锚点恢复;rendezvous RPC 本身没有重试策略。

失败 1:工作进程在 GetMultiSliceTopology 上超时

工作进程的 gRPC 截止时间来自 FLAGS_megascale_topology_discovery_timeout(位于 +0x34..+0x40 的 Options 字段,一个 absl::Duration)。当协调器的 TopologyCoordinator 积累到 quorum 之前截止时间触发时,工作进程的 stub 会向 DiscoverTopologyAndAddressBindingsxla::megascale::runtime::CommunicationBackend::DiscoverTopologyAndAddressBindings0x1ccacb80)返回 DEADLINE_EXCEEDED,随后它会:

  1. 通过在 0x1ccacea4 构造的 StatusOr<tuple<MultiSliceTopologyAndLocationProto, EndpointAddresses>>DiscoverTopologyAndAddressBindings 内部的 absl::StatusOr<...>::StatusOr 调用;参数设置在 0x1ccacea1)将错误返回给 XLA Megascale 运行时。 工作进程侧不会发出 "TopologyCoordinator: Unable to wait for all slices to connect..." 日志;该字符串(0x96df1d4)由协调器的析构函数发出,见失败 2。
  2. 运行时调用 CommunicationBackend::ReportError(slice_id, host_id, MegaScaleRuntimeError{...})xla::megascale::runtime::CommunicationBackend::ReportError(int, int, MegaScaleRuntimeError const&)0x1ccadbe0):这是 MegaScaleTransport.ReportError gRPC (/xla.megascale.runtime.MegaScaleTransport/ReportError),会扇入协调器的 ErrorReporter(见 错误聚合器)。MegaScaleRuntimeError 携带 error_message 字段 (xla.megascale.runtime.MegaScaleRuntimeError.error_message)和一个 ErrorType 枚举 (MegaScaleRuntimeError.ErrorType);UNRECOVERABLE_ERROR 成员是真实存在的,不过 bootstrap 超时消息文本是在运行时构造的,并不是固定的 rodata 字面量。
  3. 运行时向 PJRT 返回非 OK Status,PJRT 再将其暴露给用户代码。

如果设置了 --megascale_use_inplace_restart_for_error,运行时会尝试原地拆除并重新实例化 CommunicationBackend,而不是退出。否则进程退出,集群调度器重启它(Borg/GKE crash-loop),此时 bootstrap 从头重试。

失败 2:协调器一直没有看到足够的注册

协调器的 TopologyCoordinator 本身没有超时;Coordinator<> 基类不会调用 WaitForNotificationWithTimeout,也没有任何按实例计时器。bootstrap 时间的界限完全由每个工作进程附加的每 RPC 截止时间施加。因此,当注册不断迟到时会发生:

  1. 协调器位于 +0x88 的 pending-callback vector 增长。
  2. 周期性的 ReportStatus()xla::megascale::runtime::TopologyCoordinator::ReportStatus0x213b7ba0)继续发出 "MegaScale Topology Discovery in progress. Missing hosts (num_slices=&lt;N&gt;, num_hosts=&lt;H&gt;): [&lt;list&gt;]"0x96df232),其中包含尚未登记的 slice/host 列表。
  3. 随着各个工作进程达到自己的截止时间,gRPC 框架取消其服务器端请求。当响应最终构建出来时,协调器 vector 中的 pending callback 仍会被调用,但调用现在落在已取消的 ServerCallbackUnaryImpl 上,后者会静默丢弃响应。
  4. 当最慢的工作进程最终出现(或使用相同 (slice_id, host_id) 的重启工作进程出现)时,协调器的 IsComplete() 转为 true, CreateResponse() 运行,每个仍处于活动状态的 pending callback 都会收到响应。已取消的 callback 变成 no-op。

协调器不会中止。该进程继续运行,TopologyCoordinator 仍处于 state=1,准备接受缺失的注册。如果操作员判断 rendezvous 已无希望,必须从外部杀死协调器进程。

"TopologyCoordinator: Unable to wait for all slices to connect. The missing hosts (num_slices=&lt;N&gt;, num_hosts=&lt;H&gt;): [&lt;list&gt;]" 日志(0x96df1d4)只会在 TopologyCoordinator 未收敛就被销毁时发出,即由 xla::megascale::runtime::TopologyCoordinator::~TopologyCoordinator0x1cf511a0)调用 GetMissingHosts() 并格式化剩余 slice/host 时发出。它不是由工作进程上的 DiscoverTopology... 发出,也不是由等待期间的 ReportStatus() 发出。

一条协调器特有的日志是 "Some workers didn't report an error after 5 minutes: ..." (rodata 0xa238672):它来自 ErrorReporter::ProcessErrorDigest() 路径 (xla::megascale::runtime::ErrorReporter::ProcessErrorDigest0x1ccb7140;见 错误聚合器),而不是来自 TopologyCoordinator 本身。它在错误聚合反过来超时时触发;拓扑聚合没有这样的日志。

失败 3:重新键控 / 漂移不匹配

当工作进程以不同的 topology_args、不同的 host_addresses 或不同的 incarnation_id 重新注册时,协调器会在两个位置捕获漂移:

所有三个漂移检查都位于同一个函数中: xla::megascale::runtime::TopologyCoordinator::ProcessRequest0x1cf524c0),而不是拆分到单独的广播时路径中。两个 proto2::util::MessageDifferencer::Compare 调用(0x1cf5269d0x1cf527a4,每个调用之前都有 set_message_field_comparison(1) + ReportDifferencesToString)驱动拓扑和主机地址比较;incarnation id 则内联比较。每个不匹配都是硬性 reject:下面的消息会被构建进 MakeErrorImpl<3> (INVALID_ARGUMENT) Status 并被返回(该函数在匹配位置 return Error),而不是记录日志后继续。三条错误消息是:

  • "Received topology that differs from previously registered topology at same sliceID. SliceID: $0 Previous HostId: $1 New HostId: $2 Addresses: $3 Diff: $4"0x9b27486),当 topology_args 不同时触发(在 0x1cf527a4 处第二个 Compare 之后)。
  • "Received host address mapping that differs from previous mapping SliceID: $0 HostId: $1 Prev Address: $2 New Addresses: $3"0x9c14204),当 host_addresses 不同时触发(在 0x1cf5269d 处第一个 Compare 之后)。
  • "Received incarnation ID that is different from previous incarnation ID. SliceID: $0 HostId: $1 Prev IncarnationId: $2 New IncarnationId: $3"0x9c14456),当只有 incarnation id 发生变化时触发。这是静默工作进程重启的信号。

所有三条消息都由 absl::SubstituteAndAppendArray 组装(反编译中对应的字面长度分别为 153 / 122 / 139),进入返回的 INVALID_ARGUMENT Status。发生漂移的注册会被拒绝:违规工作进程的 GetMultiSliceTopology RPC 返回错误,而不是完成。协调器针对该 (slice_id, host_id)已接受状态保持不变;它不会采纳新的(漂移后的)值。因此,以相同 args 重新注册的工作进程仍会根据缓存响应解析,但发生漂移的工作进程会得到错误。

另有一个针对日志 unique id 的按 (slice,host) 单次去重机制: LogUniqueIds(内联到 xla::megascale::runtime::Communicator::Create0x1cca9aa0)在 0x223717c00x223717c40x223717c8 处持有三个 int 槽位 last_ids.0/.1/.2,由 unique_id_mutex 保护。这套机制限制工作进程侧响应路径上的 unique-id 日志频率;它不会发出上面的三条协调器侧错误消息。

要强制真正重新 bootstrap,操作员必须杀死协调器进程;协调器重启后,新的 TopologyCoordinator 从空状态开始,每个工作进程都必须重新发出 GetMultiSliceTopology

Barrier 失败

BarrierCoordinator 采用相同的 RPC 超时模型。barrier 超时作为 gRPC 客户端截止时间在带外携带,不是 proto 字段;BarrierRequest 字段 4 是 num_participants(会与协调器存储的数量校验),每次调用的截止时间来自 FLAGS_tf_tpu_preexecution_barrier_timeout(默认 30 s)。见 跨主机 Barrier §5。当参与者超时时:

  1. 工作进程侧记录本地 deadline-exceeded 错误。
  2. BarrierCoordinator 被销毁且并非所有参与者都已登记时,它的析构函数 (xla::megascale::runtime::BarrierCoordinator::~BarrierCoordinator0x1cf55760)发出 "BarrierCoordinator: Unable to wait for all slices to connect. Saw "0xa1b93bb)`+ "<K>" + " of " + "<NumW>"
    • " expected participants. Seen hosts: " + GetSeenHosts()。 三个 rodata 片段(Saw of expected participants. Seen hosts: )通过 LogMessage::CopyToEncodedBuffer拼接,主机列表来自BarrierCoordinator::GetSeenHosts()。这与 topology coordinator 一样,是析构时未收敛模式,不是ReportStatus()` 发出。
  3. 运行时通过 ReportError 将失败的 barrier 视为 UNRECOVERABLE_ERROR

如果 --xla_tpu_enable_megascale_barrier=false,整个 barrier 机制会被绕过: BarrierCoordinator 永远不会实例化,也不会发出 Barrier RPC。这是调试/测试开关;生产部署始终启用它。

HeartBeat 失败(bootstrap 后)

bootstrap 完成后,运行时会启动 StartHeartBeat()0x1ccade60),定期 ping 每个 peer。心跳失败会沿以下路径级联:

  • "Failed to send heartbeat to <peer>"0xa1ec1d8
  • "Failed to perform heartbeat check"0x863656b
  • "Stop heartbeat check watchdog"0x8655783

三个由 flag 控制的中止策略:

Flag心跳失败的影响
--megascale_use_inplace_restart_for_failed_heartbeat"Aborting (w/ restart) due to failed heartbeat."0x9ffa7d9)——运行时原地拆除并重建 CommunicationBackend
--megascale_restart_on_failed_heartbeat (without inplace)"Aborting (w/o restart) due to failed heartbeat."0x9ffa7a9)——进程退出,由调度器重启
Neither flag"Terminating the process due to failed heartbeat."0x9ffa778)——进程退出,不重启

心跳在逻辑上不是 bootstrap 的一部分;它只在 DiscoverTopologyAndAddressBindings 返回 OK 后运行。但它继承 bootstrap 期间构建的地址表,因此其失败模式会隐式验证该表。

传播到 ErrorReporter / RapidEye

每一种调用 ReportError 的 bootstrap 失败模式最终都会进入协调器的 MegascaleErrorAggregator(见 错误聚合器)。MegaScaleRuntimeError.ErrorType 携带 UNRECOVERABLE_ERROR 成员(这里未独立确认其数值序号)。聚合器的分类器会将其映射到 RapidEyeErrorDigestProto.Cause 枚举成员 UNRECOVERABLE_ERROR (与 BAD_TPU_CHIPNETWORKING_ISSUEDATA_INPUT_STALL 并列的真实 Cause 值),并从 xla::megascale::runtime::MegascaleErrorAggregator::LogErrorDigest0x213b42c0)发出诊断模板 "Some workers have halted with an unrecoverable error: ..."0xa23e476)。

如果设置了 --megascale_rapideye_error_digest_log_path,包含失败主机列表的 digest 会通过 CloudRapidEyeLogger 写入该路径。否则失败只会捕获在协调器上的 LOG(ERROR) 轨迹中。完整的保留和消费链见 错误聚合器

不存在什么

  • 没有 bootstrap 侧重试。工作进程不会在瞬时失败时内部重试 GetMultiSliceTopology
  • rendezvous 本身没有协调器侧超时。只要工作进程持续在各自每 RPC 截止时间前到达,rendezvous 就可以一直等待。
  • 已组装拓扑没有磁盘持久化。协调器重启会丢失缓存。
  • rendezvous payload 没有备用通道(UDS、共享内存)。所有内容都通过 TCP 上的 gRPC 传输。
  • pending callback 没有有界队列。持有数万个 pending 工作进程的协调器进程会把它们全部保留在内存中。

交叉引用

  • Bootstrap › 概览 — 本页枚举其失败路径的生命周期
  • 收敛 — 这些失败从中分支出来的成功路径
  • 工作进程注册 — 其校验会产生 INVALID_ARGUMENT 拒绝的请求
  • 错误聚合器 — 每个 ReportError 最终被分类进 RapidEyeErrorDigestProto.Cause 的位置
  • ICI 交接 — 与 Megascale 路径并行运行的 tpunetd 侧失败表面