已开启
[Usage]: API一致性说明:torch.distributed.elastic.rendezvous.etcd_rendezvous.EtcdRendezvousHandler, torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.create_backend等一系列api的一致性检测 #1877
zjucn创建于  5月11日
zjucn
zjucn
5月11日 创建

在提交新问题之前,请确保您已经在社区中搜索过相关问题,并使用了社区中提供的资源/工具后,仍未找到满意的解决方式。

环境信息

环境信息

  • 操作系统:乌班图
  • 昇腾硬件信息:800I A2
  • CANN软件版本:8.5.0
  • 安装的对应软件版本:torch torch-npu 2.7.1、2.9.0、2.10.0、2.11.0

使用场景及问题

本文分析以下 PyTorch elastic rendezvous etcd 相关 API 在 torch-npu 环境下的验证和适配方案:

torch.distributed.elastic.rendezvous.etcd_rendezvous.EtcdRendezvousHandler
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.create_backend
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.get_state
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.name
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.set_state

这组 API 属于 torch.distributed.elastic.rendezvous 模块中的 etcd rendezvous 控制面接口,主要用于 elastic 分布式训练中 worker 的注册、会合、状态同步、rank 分配、world size 确定以及 rendezvous 状态的持久化管理。

经分析,这组 API 本身不涉及 NPU tensor、NPU kernel、HCCL 数据通信或 NPU 设备内存管理,其行为主要依赖 Python 层控制逻辑、etcd 服务端、python-etcd 客户端以及 PyTorch elastic rendezvous 通用机制。因此,对这组 API 的验证重点是官方上游控制面用例能否在 torch-npu 环境直接执行,以及是否存在需要 torch-npu 额外适配的设备侧逻辑。

1.1 Api功能

核心功能

torch.distributed.elastic.rendezvous.etcd_rendezvous.EtcdRendezvousHandler

EtcdRendezvousHandler 是 PyTorch elastic rendezvous 模块中基于 etcd 的 rendezvous handler,用于在分布式训练 worker 启动时完成 rendezvous 流程。

rendezvous 可以理解为分布式训练 worker 的“会合点”。多个 worker 在正式初始化分布式训练前,需要到同一个共享后端登记自己。rendezvous 逻辑会根据当前到达的 worker 数量、最小节点数、最大节点数和任务状态,决定哪些 worker 可以进入本轮训练,并为它们分配 rankworld_size。在 etcd 实现中,这些状态保存在 etcd key-value 存储中。

EtcdRendezvousHandler 的主要职责包括:

  • 通过 next_rendezvous() 等待并完成一次 rendezvous,返回 RendezvousInfo
  • 通过内部 EtcdRendezvous 逻辑确定当前 worker 的 rank 和整体 world_size
  • 创建 EtcdStore,为后续分布式初始化提供 key-value store。
  • 通过 get_backend() 返回后端名称 "etcd"
  • 通过 is_closed()set_closed()shutdown() 管理 rendezvous 生命周期。
  • 通过 num_nodes_waiting() 查询当前是否有新 worker 等待进入下一轮 rendezvous。
  • 通过 get_run_id() 返回当前 rendezvous 的 run id。
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend

EtcdRendezvousBackend 是 PyTorch dynamic rendezvous 体系中的 etcd 后端实现,负责将 dynamic rendezvous 的状态对象保存到 etcd 中,并提供并发安全的状态读取和状态更新能力。

它的核心职责包括:

  • 根据 run_id 和可选 key_prefix 确定 rendezvous state 在 etcd 中的 key。
  • 将二进制状态 bytes 通过 base64 编码后写入 etcd。
  • 从 etcd 中读取 base64 状态并解码为 bytes
  • 使用 etcd 的 modifiedIndex 作为 token,支持 compare-and-set 语义。
  • 在 etcd 连接失败时抛出 RendezvousConnectionError
  • 在 state 数据损坏时抛出 RendezvousStateError
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.create_backend

create_backend 是 etcd dynamic rendezvous backend 的工厂函数。它接收 RendezvousParameters,解析 endpoint、protocol、read timeout、证书等配置,创建 etcd client,并返回:

(EtcdRendezvousBackend, EtcdStore)

其中,EtcdRendezvousBackend 用于保存和更新 rendezvous state,EtcdStore 用于分布式初始化阶段的 key-value 信息交换。默认情况下,rendezvous state 存放在 /torch/elastic/rendezvous/<run_id>,store 数据存放在 /torch/elastic/store

torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.get_state

get_state 用于从 etcd 中读取当前 rendezvous state。state key 不存在时返回 None;state key 存在时返回 (state, token),其中 state 是 base64 解码后的 bytestoken 是 etcd 返回的 modifiedIndex,用于后续 CAS 更新。如果 etcd 连接失败,则抛出 RendezvousConnectionError;如果 etcd 中的数据不是合法 base64,则抛出 RendezvousStateError

torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.name

nameEtcdRendezvousBackend 的后端名称属性,固定返回 "etcd-v2"

torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.set_state

set_state 用于向 etcd 写入新的 rendezvous state,并通过 token 实现并发安全更新。输入的 state: bytes 会先 base64 编码,再写入 etcd。不传 token 时,只允许在 state key 不存在时创建新 state;传入当前 token 时,通过 prevIndex=token 执行 CAS 更新。

其返回语义如下:

  • 如果写入成功,返回 (new_state, new_token, True)
  • 如果 token 过期、为空或非法,不覆盖当前 state,返回 (current_state, current_token, False)
  • 如果 etcd 连接失败,抛出 RendezvousConnectionError

核心特性

这组 API 的核心特性是 elastic 分布式训练中的控制面协调能力,而不是设备侧计算能力。

其主要能力包括:

  • 基于 etcd 的 worker rendezvous 状态管理。
  • 分布式 worker 的到达、等待、关闭和重新 rendezvous 控制。
  • 使用 run_id 区分不同训练任务。
  • 使用 etcd key-value 存储保存 rendezvous state。
  • 使用 token/CAS 防止多个 worker 并发更新状态时互相覆盖。
  • 使用 EtcdStore 为分布式初始化提供共享 key-value store。

这些能力都属于分布式训练的协调面。它们不执行矩阵计算、张量拷贝、NPU 算子调度,也不要求 tensor 位于 NPU 设备上。因此,是否能够运行主要取决于 PyTorch elastic 模块、etcd 服务端和 python-etcd 客户端是否可用,而不是取决于 NPU kernel 是否适配。

1.2 npu适配方案

1.2.1 测试用例适配

针对上述 API,不需要新增 torch-npu 专项测试用例,也不需要对 torch-npu 生产代码进行 patch。需要注意的是,PyTorch 2.7.1、2.9.0、2.10.0 的官方 etcd_server_test.py 存在测试用例问题,在 torch-npu 对应版本环境验证时需要对该测试文件做 patch;PyTorch 2.11.0 可直接使用官方测试。

原因如下:

  1. API 行为属于 elastic rendezvous 控制面逻辑,不涉及 NPU tensor 或 NPU 算子。
  2. 上游 PyTorch 已经存在针对 etcd rendezvous backend 的官方测试,覆盖 state 读写、CAS token、backend 创建、store 读写和单 worker rendezvous 等行为。
  3. 在 NPU 环境中执行这些测试时,主要验证的是 etcd 环境依赖是否完整,而不是验证 NPU 后端能力。
  4. 如果直接新增 NPU 专项用例,容易把 etcd 二进制、python-etcd、etcd v2 API、localhost 端口等外部环境问题误判为 torch-npu API 兼容性问题。

本次验证使用 PyTorch 官方已有测试用例,覆盖该组 API 的控制面行为。涉及的测试文件包括:

  • pytorch/test/distributed/elastic/rendezvous/etcd_rendezvous_backend_test.py
  • pytorch/test/distributed/elastic/rendezvous/rendezvous_backend_test.py
  • pytorch/test/distributed/elastic/rendezvous/etcd_rendezvous_test.py
  • pytorch/test/distributed/elastic/rendezvous/etcd_server_test.py

上述测试依赖本地可执行的 etcd 服务端程序和 Python etcd 客户端依赖。PyTorch 的 EtcdServer 会启动本地 etcd 进程,并使用 etcd v2 API 完成 rendezvous 状态读写;因此测试环境需要提供支持 v2 API 的 etcd 服务端。若缺少 etcd 命令或 python-etcd 客户端,测试会在启动或连接 etcd 阶段失败,此类失败属于测试环境依赖问题,不属于 NPU 设备侧兼容性问题。

API 名称 功能说明 官方验证测试类/方法 验证详情
torch.distributed.elastic.rendezvous.etcd_rendezvous.EtcdRendezvousHandler 基于 etcd 的 elastic rendezvous handler,用于完成 worker 会合、rank/world size 分配和 store 创建 EtcdRendezvousTest.test_etcd_rdzv_basic_params / EtcdRendezvousTest.test_etcd_rdzv_additional_params / EtcdRendezvousTest.test_get_backend / EtcdServerTest.test_etcd_server_with_rendezvous 验证 handler 可由 rendezvous 参数创建,get_run_id() 返回正确 run id,get_backend() 返回 "etcd",并可在单 worker 场景下完成 rendezvous,返回有效 store、rank 和 world size
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.create_backend 根据 RendezvousParameters 创建 EtcdRendezvousBackendEtcdStore CreateBackendTest.test_create_backend_returns_backend / test_create_backend_returns_backend_if_protocol_is_not_specified / test_create_backend_returns_backend_if_read_timeout_is_not_specified / test_create_backend_raises_error_if_etcd_is_unreachable / test_create_backend_raises_error_if_protocol_is_invalid / test_create_backend_raises_error_if_read_timeout_is_invalid / test_get_waits_for_store_prefix_key 验证 backend 和 store 创建、默认参数、read timeout、协议校验、连接错误、非法参数、state 写入路径、store 写入路径以及 store get 等待行为
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend dynamic rendezvous 的 etcd 状态后端,负责保存和更新 rendezvous state EtcdRendezvousBackendTest 结合 RendezvousBackendTestMixin 验证 backend 初始化后可读写 rendezvous state,并符合通用 RendezvousBackend 行为约定
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.get_state 从 etcd 读取 rendezvous state,返回 (state, token)None RendezvousBackendTestMixin.test_get_state_returns_backend_state / test_get_state_returns_none_if_backend_state_does_not_exist / test_get_state_raises_error_if_backend_state_is_corrupt 验证可读取已写入 state,空 state 返回 None,损坏的非 base64 state 抛出 RendezvousStateError
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.name 返回 backend 名称 "etcd-v2" CreateBackendTest.test_create_backend_returns_backend 验证 backend.name == "etcd-v2"
torch.distributed.elastic.rendezvous.etcd_rendezvous_backend.EtcdRendezvousBackend.set_state 将 rendezvous state 写入 etcd,并使用 token/CAS 保证并发安全 RendezvousBackendTestMixin.test_set_state_sets_backend_state_if_it_does_not_exist / test_set_state_sets_backend_state_if_token_is_current / test_set_state_returns_current_backend_state_if_token_is_old / test_set_state_returns_current_backend_state_if_token_is_none / test_set_state_returns_current_backend_state_if_token_is_invalid 验证首次写入、当前 token 更新、旧 token 不覆盖、无 token 不覆盖已有 state、非法 token 不覆盖已有 state,并检查返回的 has_set 语义

1.2.2 测试用例文件介绍

./pytorch/test/distributed/elastic/rendezvous/etcd_rendezvous_backend_test.py 是 PyTorch 官方提供的 etcd dynamic rendezvous backend 测试文件。该文件在 setUpClass 中启动本地 EtcdServer,并在测试结束后停止服务。测试主体分为 EtcdRendezvousBackendTestCreateBackendTest

EtcdRendezvousBackendTest 继承 RendezvousBackendTestMixin,通过真实 etcd client 构造 EtcdRendezvousBackend,并复用通用 backend 行为测试,覆盖 get_state()set_state() 的核心语义。它验证 state 可读回、空 state 返回 None、损坏 state 抛错、首次写入成功、当前 token 更新成功、旧 token 更新失败、无 token 更新已有 state 失败,以及非法 token 更新失败。

CreateBackendTest 直接覆盖 create_backend()。它验证创建出的 backend 名称为 "etcd-v2",store 类型为 EtcdStore,read timeout 被正确传递,并进一步检查 backend.set_state() 会把 base64 编码后的 state 写入 /torch/elastic/rendezvous/<run_id>store.set() 会把 base64 编码后的 key/value 写入 /torch/elastic/store。此外,它还覆盖 protocol 默认值、read timeout 默认值、etcd 不可达、非法 protocol、非法 read timeout,以及 store.get() 等待另一个线程写入 key 的阻塞语义。

./pytorch/test/distributed/elastic/rendezvous/etcd_rendezvous_test.py 是 PyTorch 官方提供的 etcd rendezvous handler 测试文件。该文件启动本地 EtcdServer,并通过 create_rdzv_handler() 创建 EtcdRendezvousHandler。测试覆盖最小参数创建、附加参数创建、get_run_id()get_backend()

./pytorch/test/distributed/elastic/rendezvous/etcd_server_test.py 主要验证 EtcdServer,其中 test_etcd_server_with_rendezvous 会进一步将 EtcdServerEtcdRendezvousEtcdRendezvousHandler 结合使用,验证单 worker 场景下可以完成 rendezvous,返回有效 store、rank == 0world_size == 1。该测试可作为 EtcdRendezvousHandler.next_rendezvous() 的基础集成验证。

其中,2.7.1、2.9.0、2.10.0 版本的 etcd_server_test.py 需要 patch 后执行;2.11.0 版本不需要 patch。该 patch 仅修正测试用例构造 rendezvous handler 的方式,不涉及 torch-npu 生产代码或 API 行为变更。

1.2.3 API适配方案(不需要)

本组 API 无需做 torch-npu 代码级适配。

原因如下:

  • EtcdRendezvousHandler 的核心行为是 rendezvous 状态机、worker 注册、rank/world size 分配和 store 创建,不涉及 NPU 算子。
  • create_backend 的核心行为是解析 rendezvous 参数、创建 etcd client、创建 EtcdRendezvousBackendEtcdStore,不涉及 NPU 设备。
  • EtcdRendezvousBackend.get_state 只从 etcd 读取 base64 编码的状态并解码。
  • EtcdRendezvousBackend.set_state 只向 etcd 写入 base64 编码的状态,并使用 etcd CAS token 防止并发覆盖。
  • EtcdRendezvousBackend.name 只返回固定字符串 "etcd-v2"
  • EtcdStore 的读写行为属于 key-value store 通信,不是 NPU tensor 计算。

因此,该组 API 的可用性主要取决于以下外部条件:

  • Python 环境是否能导入 etcd 客户端包。
  • 系统路径或 TORCHELASTIC_ETCD_BINARY_PATH 是否能找到可执行的 etcd 服务端。
  • etcd 服务端是否支持 v2 API。
  • 本地端口是否可绑定,localhost 网络是否可访问。
  • 测试进程是否具备创建临时目录和启动子进程的权限。

这些条件均属于测试环境或系统依赖,不属于 torch-npu 的 NPU 后端适配范围。

1.3 验证结果

在 torch torch-npu 2.7.1、2.9.0、2.10.0、2.11.0 环境下,复用 PyTorch 官方 etcd rendezvous 测试进行验证。其中 etcd_rendezvous_backend_test.pyetcd_rendezvous_test.py 可直接执行;etcd_server_test.py 在 2.7.1、2.9.0、2.10.0 中需要应用 patch 后执行,2.11.0 可直接执行。

测试命令如下:

cd rendezvous

python -m unittest -v etcd_rendezvous_backend_test
python -m unittest -v etcd_rendezvous_test
python -m unittest -v etcd_server_test

etcd_rendezvous_backend_test 验证结果摘要如下:

Ran 15 tests in 4.255s

OK

etcd_rendezvous_test 验证结果摘要如下:

Ran 3 tests

OK

修改后的 etcd_server_test 验证结果摘要如下:

Ran 2 tests

OK

测试过程中可能出现 etcd 服务端自身的 warning,例如 --enable-v2 is deprecated、单端口运行提示、临时目录权限提示等。这些日志来自 etcd 服务端,不影响用例结果。

验证结论

验证结果表明,上述 etcd rendezvous API 在 torch-npu 2.7.1、2.9.0、2.10.0、2.11.0 环境下可复用 PyTorch 官方测试进行控制面验证。

该组 API 的主要功能是基于 etcd 完成 rendezvous 状态存储、worker 会合、rank/world size 分配、store 创建和 CAS 状态更新,不涉及 NPU tensor、NPU kernel 或 HCCL 数据通信。因此,在 torch-npu 环境下无需做代码级适配,也不需要新增 NPU 专项用例,仅需对 etcd_server_test.py 文件进行修改。

欢迎加入社区,感谢您对社区的贡献。

likedislike
ascend-robotascend-robot成员
5月11日 添加了label:usage
zjucnzjucn
5月12日 修改了issue 的描述
zjucnzjucn
5月12日 修改了issue 的描述
zjucnzjucn
5月13日 修改了issue 的描述
zjucnzjucn
5月13日 修改了issue 的描述
zjucnzjucn
5月13日 关联了pull request:test: adapt etcd rendezvous upstream test
zjucnzjucn
5月13日 关联了pull request:test: adapt etcd rendezvous upstream test
zjucnzjucn
5月13日 关联了pull request:test: adapt etcd rendezvous upstream test
zjucnzjucn
5月13日 关联了pull request:test: adapt etcd rendezvous upstream test
Ddinglaiping成员
5月14日 添加了label:event: api-consistency
chenrayraychenrayray成员
7月4日 issue类型由 Bug-Report 改变为 任务
ascend-robotascend-robot成员
7月8日 关联了看板:MindStudio ISSUE管理
TorchNPU-BotTorchNPU-Bot成员
7月28日 添加了label:bot-triaged
TorchNPU-Bot
TorchNPU-Bot成员
7月28日 评论:

检测到当前 issue 已关联 PR !35498,自动添加标签:bot-triaged

likedislike