协调器选举
Megascale 不运行投票。协调器是启动器(Borg、GKE,或手写的作业脚本)通过 MEGASCALE_COORDINATOR_ADDRESS 和 MEGASCALE_PORT 指定的进程。每个到达 DiscoverTopologyAndAddressBindings (@0x1ccacb80) 的进程都会通过 InitializeCoordinator (@0x1ccad600) 安装一个 TopologyCoordinator;随后从该 TopologyCoordinator 的状态读取协调器与工作进程的角色: CommunicationBackend::StartHeartBeat (@0x1ccade60) 调用位于 +0x1a0 的对象上的虚方法,并根据它是否返回 2(协调器)进行分支,否则为工作进程。因此该决策是确定性的:它来自启动器在每个节点上设置环境变量的方式。
本页中的所有 VA、偏移、源码行号和字符串都已逐字节对照 IDA 反编译结果以及
libtpu.so(wheel 0.0.40,build-id89edbbe81c5b328a958fe628a9f2207d)的objdump/strings验证。
选举输入
CommunicationBackend::PopulateOptionsFromFlags() (@0x1ccab3c0) 将四个 flag 读入每进程的 Options 结构,字节偏移如下确认: FLAGS_megascale_coordinator_address → +0x00, FLAGS_megascale_port → +0x30 (int32), FLAGS_megascale_port_name → +0x18, FLAGS_megascale_topology_discovery_timeout → +0x34。 其余行由其他路径填充;标记为 INFERRED 的偏移未在此函数中确认。
| 来源 | 复制到 Options 的字段 | 影响 |
|---|---|---|
FLAGS_megascale_coordinator_address (MEGASCALE_COORDINATOR_ADDRESS) | Options.coordinator_address (+0x00 处的 string) | 协调器的众所周知端点。每个进程都会解析此地址;本地接口匹配的那个进程成为协调器。 |
FLAGS_megascale_port (MEGASCALE_PORT) | Options.port (+0x30 处的 int32) | 本地 MegaScaleTransport gRPC 服务器的绑定端口。必需项;未设置时 libtpu 会记录 "megascale_port is not set." 并中止。 |
FLAGS_megascale_port_name | Options.port_name (+0x18 处的 string) | 由主机端口分配服务解析的备用命名端口。设置后优先于数字端口。 |
FLAGS_megascale_num_slices (MEGASCALE_NUM_SLICES) | 通过 xla_megascale 传递 → InitializeCoordinator(num_slices) | 此作业的总 slice 数。协调器的 TopologyCoordinator 会等待恰好这么多 slice 注册。 |
FLAGS_megascale_slice_id (MEGASCALE_SLICE_ID) | Options.slice_id (+0x58 处的 int32,INFERRED) | 此进程的 slice id。工作进程把它放入每个请求;协调器将其作为 flat_hash_map<int, SliceState> 中的键。 |
FLAGS_megascale_topology_discovery_timeout | Options.topology_discovery_timeout (+0x34 处的 absl::Duration,+0x3c 处的 int64 + int32) | 应用于 GetMultiSliceTopology 的每 RPC 截止时间。作为总 rendezvous 时间的上界。 |
FLAGS_tf_tpu_preexecution_barrier_timeout | Options.barrier_timeout (+0x44..+0x50 处的 absl::Duration,INFERRED) | 应用于后续 Barrier 调用的每 RPC 截止时间。 |
FLAGS_megascale_transport_type (MEGASCALE_TRANSPORT_TYPE) | Options.transport_type | "grpc"(默认)选择 GrpcTransport;"chaotic_good_legacy" 选择实验性的 Chaotic-Good 传输。 |
FLAGS_megascale_transport_numa_node | Options.transport_numa_node | 传输线程的可选 NUMA 亲和性提示。 |
FLAGS_megascale_authentication (MEGASCALE_AUTHENTICATION) | Options.auth_method | 选择 gRPC ServerCredentials。非 Google 内部构建默认不安全。 |
运行时在启动时发出单条 instrumentation 日志行,回显选举输入:
megascale_coordinator_address:$0 megascale_port: $1 megascale_port_name: $2 topology_discovery_timeout: $3 barrier_timeout: $4
```text
(rodata `0x9b27325` 处的字面 absl 替换模板;`$0..$4` 在运行时填充)。结合
`Instrumentations: megascale_num_slices:` 和 `Instrumentations: megascale_slice_id:`
(rodata `0xa23ae2a`、`0xa282bf7`),这些行可以唯一标识每个进程正在扮演的角色。
## 选举序列
```text
process startup
│
▼
xla_megascale runtime construction
│
▼
CommunicationBackend::Create(options, alloc_cb, free_cb,
transport_factory, ...)
│
▼
new CommunicationBackend(options, alloc_cb, free_cb)
│ TracedMutex (kind=6) at +0xe0
│ RandenPool seed_seq
│
▼
transport_factory(callbacks) // pluggable; default: GrpcTransport
│
▼
GrpcTransport::Init({port = Options.port, ...})
│ attempts to bind Options.port
│ on success: registers WithCallbackMethod_* handlers
│ on failure: returns NOT_OK; CommunicationBackend stores it at +0x148
│
▼
runtime calls DiscoverTopologyAndAddressBindings(
local_slice_id, topology_args, local_host_id, num_slices)
│ // @0x1ccacb80
▼
InitializeCoordinator(num_slices) // @0x1ccad600, called unconditionally
│ if (this->+0x1a0 != 0) // TopologyCoordinator already installed?
│ return MakeErrorImpl<13>( // INTERNAL, line 1480
│ "Coordinator was already initialized. Re-init not supported.");
│ TopologyCoordinator* tc = new TopologyCoordinator(num_slices); // operator new(0x108)
│ this->+0x1a0 = tc; // TC installed
│ this->+0x1a8 = new ErrorReporter(tc, threadpool_, cb, clock);
│ return 1; // OK
│
▼
TopologyCoordinator::TopologyCoordinator(num_slices) // @0x213b7a40
│ CHECK(num_expected_slices_ > 0) // topology_coordinator.cc:55
│ Log (topology_coordinator.cc:56):
│ "Megascale Topology Coordinator started for " << num_slices << " slices"InitializeCoordinator 实际检查什么
CommunicationBackend::InitializeCoordinator 不会把 coordinator_address 字符串与本地接口比较。它唯一的保护是幂等性检查: 0x1ccad600..0x1ccad62a 处的序言读取 TopologyCoordinator 槽位,并拒绝第二次安装。
1ccad600: 48 83 bf a0 01 00 00 00 cmpq $0x0,0x1a0(%rdi) ; TopologyCoordinator installed?
1ccad608: 74 1d je 1ccad627 ; not yet -> install it
1ccad60a: 48 8d 3d ... lea ...,%rdi ; "Coordinator was already initialized..."
1ccad618: be 3b 00 00 00 mov $0x3b,%esi ; length 59
1ccad61d: ba c8 05 00 00 mov $0x5c8,%edx ; source line 1480
1ccad622: e9 59 13 47 04 jmp MakeErrorImpl<13> ; INTERNAL
```text
当 `0x1a0` 已为非 NULL 时,该函数返回
`MakeErrorImpl<13>("Coordinator was already initialized. Re-init not
supported.", 59, 1480, …)`;立即数 `$0x5c8` 是 **源码行 1480**,不是工作进程路径地址。当 `0x1a0` 为 NULL 时,它分配一个 `TopologyCoordinator` (`operator new(0x108)`),将其存储到
`+0x1a0`,在 `+0x1a8` 安装一个 `ErrorReporter`,并返回 `1` (OK)。不存在
`coordinator_address != local_address` 分支,二进制中也没有
`"Coordinator address mismatch"` 字符串。
不过协调器地址是必需的:当 coordinator-address 字段为空(从
`this+0x178`/`this[47]` 读取)时,`DiscoverTopology...` 返回
`MakeErrorImpl<13>("Discovery not available without
coordinator set.", 48, 1025, …)`。
其含义是,如果作业管理器让两个进程指向同一个
`MEGASCALE_COORDINATOR_ADDRESS`+`MEGASCALE_PORT`,就会产生端口绑定冲突:只有赢得
`GrpcTransport` 绑定的进程拥有可工作的传输;另一个进程会在下一次协调器 RPC 上暴露存储在 `+0x148` 的传输初始化失败。
## 选举失败模式
1. **`MEGASCALE_COORDINATOR_ADDRESS` 为空。** 在
`DiscoverTopologyAndAddressBindings` 内部,空的 coordinator-address 字段会返回
`MakeErrorImpl<13>("Discovery not available without
coordinator set.", 48, 1025, …)`,即 `INTERNAL` 状态,并中止 bootstrap。(二进制中没有
`"megascale_coordinator_address
is empty"` 字符串。)
2. **`MEGASCALE_PORT` 未设置。** 在 rodata `0x9ff6b6d` 处记录
`"megascale_port is not set."`。运行时将其视为致命配置错误。
3. **传输未初始化 / 端口绑定失败。**
`DiscoverTopology...` 调用 `InitializeTransportLayerInternal`,并将其 Status 存储到
`+0x148` (`this[41]`);非 OK 结果会在源码行 1022 重新发出。如果运行时发出
`GetMultiSliceTopology` 时传输指针(`this[39]`,`+0x138`)仍为 NULL,代码会返回
`MakeErrorImpl<13>("Transport not initialized.", 26, 1473, …)`。
4. **两个进程都认为自己是协调器。** 要么二者都尝试绑定同一端口,其中一个如上失败;要么二者绑定不同本地端口,但向工作进程通告的地址相同,工作进程会竞态连接到先到达的那个进程。`LogUniqueIds` 的重新键控检测(见
[失败处理](failure-handling.md))会捕获由此产生的拓扑漂移,并在运行时发出警告。
## 没有做什么
没有 Raft、没有 Paxos、没有租约、没有带健康检查的 leader 选举。Megascale 假定启动器会提供唯一的
`(coordinator_address, num_slices)` 设置;如果没有,rendezvous 会退化为上面的某种失败模式。
特别是,**协调器重启会丢失 bootstrap 状态**。新的协调器进程拥有空的
`TopologyCoordinator`;已经收到原始响应的工作进程会继续运行,但任何新的工作进程注册都必须等待整个集群重新注册。当前二进制没有已组装
`MultiSliceTopologyInfo` 的磁盘缓存,也没有启动时的重建路径。
## 交叉引用
- `CommunicationBackend::InitializeCoordinator` — `0x1ccad600`
- `CommunicationBackend::DiscoverTopologyAndAddressBindings` — `0x1ccacb80`
- `CommunicationBackend::StartHeartBeat` — `0x1ccade60`
- `CommunicationBackend::PopulateOptionsFromFlags` — `0x1ccab3c0`
- `TopologyCoordinator::TopologyCoordinator` — `0x213b7a40`
- [失败处理](failure-handling.md) — 心跳丢失和重新键控检测