执行摘要
- 一句话:引入
RayWorkerManager 骨架与工作器规格入口,为统一工作器生命周期管理奠基。
- 推荐动作:本 PR 值得相关架构团队和负责 Rollout 模块的工程师精读。它不是一个功能性的变更,而是一个重要的架构基础搭建。建议关注:
- 抽象设计:
RayWorkerManager 作为单一管理器的设计,以及通过 specs 模块聚合不同工作器规格的模式,是后续所有工作器管理重构的基石。
- 重构路径:理解
wiring.py 如何将启动流程从三个训练入口中抽取出来,这为未来支持非 Ray 部署模式(如注释中提到的 Kubernetes)预留了扩展点。
- TODO 规划:仔细阅读代码中的 TODO 注释,它们清晰地指出了当前实现的差距和下一步的演进方向。
对于普通贡献者,了解此 PR 的作用即可,无需深入细节。
功能与动机
本 PR 是对 Issue #1837 "Tracking issue for refactoring and enhancements" 的响应。其核心动机在于构建一个统一的工作器管理抽象层 (RayWorkerManager),以解耦并集中管理不同类型的 Ray 工作者(如路由器、会话服务器、推理引擎)的启动、寻址与生命周期,为后续移除硬编码、支持新的部署模式(如 Kubernetes 原生模式)以及实现更灵活的资源管理(如动态端口分配)奠定架构基础。PR body 明确指出这是重构链的一环。
实现拆解
- 引入工作器管理骨架:在
miles/utils/workers/ray_worker_manager.py 中创建 RayWorkerManager 类。该类目前仅包含 launch(创建远程 Actor)和 instance(按名称获取 Actor)两个静态方法作为接口,核心逻辑留待后续 PR 实现。
- 创建工作器启动接入点:新增
miles/ray/wiring.py 文件,提供 launch_worker_manager 公共函数。该函数协调整个启动流程:调用 compute_specs 计算工作器规格,调用 create_placement_groups 分配资源,并最终调用 RayWorkerManager.launch 启动管理器 Actor。同时返回 Placement Groups 句柄,供后续组件使用。
- 建立工作器规格汇总机制:新增
miles/ray/specs/ 模块。其中 entrypoint.py 定义 compute_specs 函数,作为汇总各类工作器规格的单一入口;inference.py 定义了 specs_router、specs_session_server 和 specs_inference_engine 三个规格计算函数(目前返回 None)。这建立了一个声明式的工作器规格框架。
- 重构训练入口的资源分配:修改
train.py、train_async.py 和 train_multi_lora_async.py,将原先直接调用 create_placement_groups 获取 pgs 的逻辑,替换为调用 launch_worker_manager(args) 并接收 (_handle, pgs)。这改变了程序启动的依赖注入路径,将 WorkerManager 的启动提前到 Placement Group 分配之后。
- 配套文件:创建空的
miles/ray/specs/__init__.py 以使其成为 Python 包。
配套测试:本 PR 未包含直接的单元测试文件变更。这是合理的,因为主要新增的是骨架代码和接入点,真实逻辑的测试将在后续 PR(如为 RayWorkerManager 添加实际功能时)中补充。
关键文件:
miles/utils/workers/ray_worker_manager.py(模块 工作器管理;类别 source;类型 core-logic;符号 RayWorkerManager, launch, instance): 核心新文件,定义了未来统一管理工作器生命周期的 RayWorkerManager 骨架类,是本次重构引入的关键抽象。
miles/ray/wiring.py(模块 接线入口;类别 source;类型 core-logic;符号 launch_worker_manager, _launch_ray_worker_manager): 核心新文件,提供了启动 WorkerManager 和分配资源的公共入口函数 launch_worker_manager,是连接训练入口与新架构的接入点。
miles/ray/specs/inference.py(模块 工作器规格;类别 source;类型 core-logic;符号 specs_router, specs_session_server, specs_inference_engine): 核心新文件,定义了路由器、会话服务器、推理引擎三类工作器规格的计算函数(当前为占位符),是工作器规格抽象框架的一部分。
train.py(模块 训练入口;类别 source;类型 dependency-wiring): 关键训练入口文件,修改为使用新的 launch_worker_manager 接口,展示了本次重构对现有启动流程的接入方式。
关键符号:RayWorkerManager.launch, RayWorkerManager.instance, launch_worker_manager, compute_specs, specs_router, specs_session_server, specs_inference_engine
关键源码片段
miles/utils/workers/ray_worker_manager.py
核心新文件,定义了未来统一管理工作器生命周期的 RayWorkerManager 骨架类,是本次重构引入的关键抽象。
import ray
# TODO: unique name, maybe with args.run_uuid
_ACTOR_NAME = "ray_worker_manager"
class RayWorkerManager:
@staticmethod
def launch(args, specs, pgs):
"""启动一个远程的 WorkerManager Actor。
当前为骨架实现,仅创建并返回 Actor 句柄。
TODO: 实现实际的 Actor 逻辑,用于管理 specs 中定义的工作器。"""
return ray.remote(RayWorkerManager).options(name=_ACTOR_NAME).remote()
@staticmethod
def instance() -> ray.actor.ActorHandle:
"""获取已存在的、通过名称注册的 WorkerManager Actor。"""
return ray.get_actor(_ACTOR_NAME)
# TODO: implement ( 例如 start_workers, stop_workers, get_worker_addresses 等方法 )
miles/ray/wiring.py
核心新文件,提供了启动 WorkerManager 和分配资源的公共入口函数 launch_worker_manager,是连接训练入口与新架构的接入点。
from miles.ray.placement_group import create_placement_groups
from miles.ray.specs.entrypoint import compute_specs
from miles.utils.workers.ray_worker_manager import RayWorkerManager
def launch_worker_manager(args):
"""启动工作器管理器的公共入口。
TODO: 在 K8s 原生模式下提前返回。"""
return _launch_ray_worker_manager(args)
def _launch_ray_worker_manager(args):
"""内部实现:计算规格 -> 分配资源 -> 启动管理器。"""
specs = compute_specs(args) # TODO: 后续应传递 specs 而非 args 给 WorkerManager
pgs = create_placement_groups(args) # TODO: 后续应由 WorkerManager 内部管理 pgs
handle = RayWorkerManager.launch(args, specs, pgs)
# TODO: 禁止外部代码直接获取 pgs,应通过 WorkerManager 提供的接口访问
return handle, pgs
评论区精华
Review 审核由 guapisolo 完成并批准。审核评论指出:"Reviewed the RayWorkerManager wiring seam introduced in #1989 through the checked stack tip at safe-merge checkpoint #2176. The remaining skeleton gaps are explicitly tracked by TODOs; no additional blockers found—LGTM." 这表明审核者认可了当前骨架结构的合理性,并认为后续的 TODO 标记足够清晰,可以作为后续 PR 的工作指引。没有发现进一步的争议或未解决的疑虑。
- 骨架代码合并审批 (other): 骨架代码结构被认可,后续实现由 TODO 跟踪。
风险与影响
-
风险:
- 集成风险:虽然本 PR 变更了训练入口的启动流程,但由于
RayWorkerManager 和 wiring 模块均为骨架代码,且 compute_specs 返回空列表,其行为与旧流程在功能上基本等价(pgs 仍被正确返回)。因此,短期内引入回归的风险较低。
- 架构风险:引入新的间接层(
wiring -> specs -> RayWorkerManager)增加了代码的复杂度。如果后续实现未能严格遵循此模式,或 TODO 项长期未完成,可能导致架构腐化。目前 launch 方法接收 args, specs, pgs 但未使用(TODO: pass in specs instead of args),以及 wiring 函数直接暴露 pgs(TODO: forbid code outside RayWorkerManager to know pg),是潜在的临时耦合点。
- 可测试性:当前骨架代码缺乏单元测试覆盖,主要风险在于接口签名(如
launch 的参数)在后续实现中可能发生改变,导致现有调用点需要同步修改。但鉴于这是重构的初期阶段,且调用点有限,此风险可控。
- 影响:对用户/系统:本 PR 本身不引入面向用户的特性或行为变更。它是一个纯粹的内部架构重构,旨在为系统带来更好的模块化和可维护性。短期内,系统行为应保持不变。
对团队:本 PR 建立了未来工作器管理的核心抽象,将引导后续多个 PR(如参考历史 PR 分析中看到的 2049, 2048, 2006 等)的开发方向。它明确了资源分配(Placement Groups)、规格计算(Specs)和生命周期管理(WorkerManager)的职责边界,有助于团队并行开发不同类型的工器器。
-
风险标记:架构过渡期耦合, 骨架代码无测试覆盖
关联脉络
- PR #2049 Add a worker provider abstraction over RayWorkerManager: 后续 PR,在本 PR 引入的 RayWorkerManager 骨架之上,进一步抽象出 WorkerProvider 来封装地址查询逻辑,是同一重构脉络的深化。
- PR #2048 Rename PortAllocator internals and pass the actor positionally: 后续 PR,重构端口分配器,可能与 WorkerManager 的资源管理功能集成,共享重构上下文。
- PR #2006 Launch inference engines through the inference engine worker spec: 后续 PR,实现了具体的工器器规格(WorkerSpec)来启动推理引擎,是填充本 PR 中 specs 模块占位符的关键步骤。
- PR #1997 Add worker specs for the sglang and miles routers: 后续 PR,为路由器添加了 WorkerSpec,同样是填充本 PR 中 specs 模块的具体实现。
- PR #1837 Tracking issue for refactoring and enhancements: 本 PR 的母 Issue,是整个重构计划的总纲,本 PR 是其中的一个子任务。
参与讨论