执行摘要
- 一句话:将 RolloutManager 拆分为 InferenceController 与 RolloutExecutor,实现职责分离。
- 推荐动作:此 PR 是一个有意义的架构重构,值得精读,尤其关注两个新类之间的职责边界划分是否清晰合理。设计决策上,将推理基础设施管理与数据执行流分离,符合单一职责原则,是合理的架构演进。建议结合后续 PR#1843 一起阅读,以获得完整的重构图景。
功能与动机
为了解决 RolloutManager 职责过多、难以维护和扩展的问题,并为未来异步和多训练器场景做准备。PR body 中明确指出这是追踪 issue #1837 “refactoring and enhancements”的一部分,旨在通过拆分使架构更清晰。
实现拆解
- 提取基础设施管理层:新增
miles/ray/rollout/inference_controller.py 文件,定义 InferenceController 类。该类从原 RolloutManager 中提取了所有与推理服务器生命周期相关的逻辑,包括服务器启动 (__init__ 中调用 start_rollout_servers)、健康监控 (_health_monitors)、引擎管理 (get_updatable_engines_and_lock, _get_updatable_server)、权重卸载/加载 (offload, onload 系列方法)、单元启停 (start_cell, stop_cell) 以及 CI 故障注入等。
- 精简执行层:将原
miles/ray/rollout/rollout_manager.py 重命名为 miles/ray/rollout/rollout_executor.py,并将类名从 RolloutManager 改为 RolloutExecutor。在该类中移除了所有被提取到 InferenceController 的代码(如服务器管理、健康监控、引擎管理、卸载/加载等),使其专注于数据生成 (generate, eval)、数据转换 (convert_samples_to_train_data) 和检查点保存/加载 (save, load) 等执行逻辑。其 __init__ 方法不再接受 pg (PlacementGroup) 参数,_eval_fleet 改为可选属性。
- 更新测试以适配新结构:同步修改
tests/fast/rollout/test_checkpoint_eval.py,将测试中对 rollout_manager_mod.RolloutManager 的所有引用(包括模块导入、object.__new__ 实例化、monkeypatch.setattr 目标)更新为 rollout_executor_mod.RolloutExecutor,确保测试覆盖到重命名后的执行器类。
关键文件:
miles/ray/rollout/inference_controller.py(模块 推理控制器;类别 source;类型 entrypoint;符号 InferenceController, init, prepare_rollout, prepare_eval): 新增的核心类,从原 RolloutManager 中提取了所有推理基础设施管理职责,是本次重构的主要产出。
miles/ray/rollout/rollout_executor.py(模块 执行器;类别 source;类型 rename-or-move;符号 RolloutManager, RolloutExecutor, init, prepare_rollout): 原 RolloutManager 重命名并精简后的新类,专注于数据生成与转换执行逻辑。
tests/fast/rollout/test_checkpoint_eval.py(模块 评估测试;类别 test;类型 test-coverage): 测试文件同步更新,将测试目标从 RolloutManager 切换到 RolloutExecutor,确保评估逻辑的测试覆盖得以保留。
关键符号:InferenceController.init, InferenceController.prepare_rollout, InferenceController.prepare_eval, InferenceController.dispose, InferenceController.offload, InferenceController.onload, InferenceController.get_updatable_engines_and_lock, RolloutExecutor.init, RolloutExecutor.generate, RolloutExecutor.eval
关键源码片段
miles/ray/rollout/inference_controller.py
新增的核心类,从原 RolloutManager 中提取了所有推理基础设施管理职责,是本次重构的主要产出。
class InferenceController:
def __init__(self, args, pg):
"""初始化推理控制器,管理推理服务器和健康监控。"""
self.pg = pg
self.args = args
# 如果仅调试训练,则不启动推理服务器
if self.args.debug_train_only:
self.servers: dict[str, RolloutServer] = {}
else:
# 启动推理服务器集群,并注册到 dashboard 和会话服务器
self.servers = start_rollout_servers(args, pg)
dashboard_hooks.register_router(args)
init_http_client(args)
start_session_server(args)
# 用于协调引擎权重更新的锁
self.rollout_engine_lock = Lock.options(num_cpus=1, num_gpus=0).remote()
self.rollout_id = -1
# 初始化评估舰队(如果配置了评估 GPU)
self.eval_fleet = EvalFleet(args, srv=self.servers["eval"]) if args.eval_num_gpus > 0 else None
# 健康监控器列表,用于容错
self._health_monitors = []
self._rollout_ft_enabled = self.args.use_fault_tolerance and "rollout" in self.args.ft_components
self._ci_fault_injection_pending = False
if not self.args.debug_train_only and self._rollout_ft_enabled:
# 为每个推理服务器组创建并启动健康监控器
for srv in self.servers.values():
for group in srv.server_groups:
monitor = RolloutHealthMonitor(group, args)
monitor.start()
self._health_monitors.append(monitor)
self._ci_fault_injection_pending = self.args.ci_test
miles/ray/rollout/rollout_executor.py
原 RolloutManager 重命名并精简后的新类,专注于数据生成与转换执行逻辑。
@ray.remote
class RolloutExecutor:
"""负责运行 rollout 并将 rollout 数据转换为训练数据的类。"""
def __init__(self, args):
# 初始化日志、事件日志、对象存储等(与之前类似)
event_logger_checkpoint.restore(args)
configure_logger(args, source=RolloutManagerProcessIdentity())
self.args = args
self.weight_version: int | None = None
# ... 其他初始化 ...
# 加载数据源和 rollout 函数
data_source_cls = load_function(self.args.data_source_path)
self.data_source = data_source_cls(args)
# ... 加载 rollout 函数的逻辑 ...
self.rollout_id = -1
self._eval_lock = asyncio.Lock()
self._eval_fleet: EvalFleet | None = None # 不再在此处初始化,可能由外部设置
self._metric_checker = MetricChecker.maybe_create(args)
# 注意:不再包含 servers、health_monitors、engine_lock 等基础设施相关属性
async def generate(self, rollout_id):
"""执行一次 rollout 数据生成并转换为训练数据。"""
start_time = time.time()
self.rollout_id = rollout_id
# ... 后续是具体的数据生成、保存、转换、拆分逻辑 ...
评论区精华
PR 本身仅有一条审查评论,由 guapisolo 批准,评论内容为:“w/ 1843 the split is complete”,表明此 PR 与后续 PR#1843 结合后,拆分工作才算完整。这暗示了本次拆分是渐进式重构的第一步,后续还有连接与异步化的工作。
- 拆分的完整性与后续步骤 (design): 确认本次拆分是初步但必要的一步,后续 PR#1843 将负责连接两个新类并使 API 异步化。
风险与影响
-
风险:
- 架构变更风险:作为核心
rollout 模块的重大重构,RolloutManager 的职责被一分为二,所有调用方(包括 train.py, train_async.py 等入口脚本)都需要相应调整。虽然本 PR 只改了三个文件,但其成功依赖于后续 PR(如 #1843)正确完成连接与适配。
- 功能遗漏风险:需要确保从
RolloutManager 中移除的代码(如 _health_monitors 管理、prepare_rollout 等)被完整且无误地迁移到 InferenceController。从 diff 看,迁移看似直接,但需关注状态(如 self.rollout_id)在新类中如何初始化与传递。
- 测试覆盖:测试文件已同步更新,但主要覆盖了
RolloutExecutor 的评估逻辑。对于 InferenceController 的新逻辑(特别是健康监控、引擎恢复等),可能需要后续测试补充覆盖。
- 影响:直接影响:所有使用 RolloutManager 的模块和脚本需要适配新的类名和职责划分。这主要影响训练入口脚本(train.py, train_async.py 等)和与之交互的调度层。
间接影响:为后续重构(PR#1843, #1844)铺平了道路,使得异步 API 和方法重命名成为可能,长远来看有利于系统维护和功能扩展。
团队影响:工程师需要理解新的架构划分(Controller 管基础设施,Executor 管数据),这有助于未来更清晰地定位问题和进行开发。
-
风险标记:核心路径变更, 架构重构
关联脉络
- PR #1843 Wire up InferenceController and RolloutExecutor and make the controller API async: 直接依赖本 PR 的拆分结果,负责将拆分后的两个类进行连接,并将 InferenceController 的 API 异步化,是完成本次重构的后续关键步骤。
- PR #1844 Rename RolloutExecutor.generate to get for future async and multi trainer scenarios: 紧接本 PR 和 #1843,进一步优化 RolloutExecutor 的 API 命名,以适应异步和多训练器场景,是重构系列的后续优化。
- PR #1837 Tracking issue for refactoring and enhancements: 本 PR 是追踪 issue #1837 中列出的重构计划的一部分,属于系统性改进的组成环节。
参与讨论