Ray Compiled Graph:面向 LLM 推理与多 GPU 分布式系统的低开销执行引擎

发布时间:2026/9/19 6:05:24
Ray Compiled Graph:面向 LLM 推理与多 GPU 分布式系统的低开销执行引擎 Ray Compiled Graph面向 LLM 推理与多 GPU 分布式系统的低开销执行引擎【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/rayRay Compiled Graphbeta是 Ray 为高性能多 GPU 工作负载尤其是 LLM 推理与分布式训练引入的静态执行图机制它提供与 Ray Core 类似的编程接口但将任务图的系统调度开销从每次调用约 1 ms 压缩到 50 μs 以下并原生支持基于 NCCL 的 GPU-GPU 通信。读完本文你将理解 Compiled Graph 相对经典 Ray Core 的动机与差异、掌握从bind()/experimental_compile()/execute()的完整编程范式、类型提示驱动的 CPU-GPU 与 GPU-GPU 数据传输以及剖析、通信-计算重叠等进阶能力和实际使用中的限制与排障要点。版本前提Ray Compiled Graph 自 Ray 2.32 起提供 API但从 Ray 2.44 起才进入 beta 状态官方推荐使用 2.44 之后的版本该功能的 API 仍在快速演进。安装时建议带上cgraphextrapip install ray[cgraph] # Ray 2.41 之前版本使用 # pip install ray[adag]为什么需要 Compiled GraphRay Core 的两点局限随着 LLM 普及在多 GPU 上编程分布式系统成为刚需。经典 Ray Core APIremote()、ray.get()能很好地跨 GPU 使用资源但官方文档ray-compiled-graph.rst明确指出两点局限每次任务启动约 1 ms 的系统开销。对于 LLM 推理这类要求亚毫秒级编排的高性能任务这个开销不可接受——例如 KV-cache 同步、跨节点张量分片传递等高频小消息场景会被协议开销吞掉。不支持 GPU 直连通信。经典 Ray 的数据传输走 CPU 侧共享内存 object store跨设备传输需要在外部库如 NVIDIA NCCL上手工搭建通信拓扑。Compiled Graph 的解决思路可以概括为提供 Ray Core-like 的 API但预先声明静态执行图换取两项核心能力对反复执行同一任务图的工作负载系统开销低于 50 μs原生支持 NCCL 的 GPU-GPU 通信底层通过 CuPy 支撑 NCCL 操作。一个直观的对比来自官方文档的示例# Ray Core API for remote execution. # 调用 recv 有约 1ms 的开销 ref receiver.recv.remote(data) ray.get(ref) # Compiled Graph for remote execution. # 调用 recv 的开销低于 50us发生在 graph.execute(data) 中 with InputNode() as inp: graph receiver.recv.bind(inp) graph graph.experimental_compile() ref graph.execute(data) ray.get(ref)两段代码语义等价——把数据发给 actor、取回结果区别在于后者先把调用关系绑定成一张图再编译、再执行。静态执行模型编译器视角的 Ray经典 Ray API 是eager立即执行的每个remote()调用即时触发调度、序列化、RPC。而 Ray Compiled Graph 是静态执行模型driver 在execute()之前就向系统完整披露了任务图结构。正是这种图已知的前提使 Ray 可以做一系列 eager 模式下做不到的优化官方文档列出了四类预分配资源Pre-allocate resources所有 channel、内存缓冲、actor 后台线程等在编译期一次性准备好运行期省去重复的分配与握手预先构建 NCCL 通信子并应用无死锁调度Prepare NCCL communicators and apply deadlock-free scheduling通信拓扑在编译期确定执行循环按预生成的调度表推进实验性自动重叠 GPU 计算与通信用计算掩盖传输延迟改善多节点性能。在快速上手示例中这种收益被量化同一个actor 回显参数的任务图经典路径单次执行约 969 μs编译后约 87 μs提升约 10 倍因为echo本身极便宜系统开销占主导。文档还解释了同节点场景下的一个具体优化若 actor 与 driver 位于同一节点Compiled Graph 会在两者之间直接走共享内存而非 RPC 传数据。编程模型InputNode、bind、compile 与 execute完整的快速上手见 quickstart核心 API 索引见 compiled-graph-api。编程范式上有三个与经典 Ray 的关键区别用InputNode上下文管理器声明运行时才提供的输入用bind()替代remote()表达惰性的 actor 任务用execute()替代提交后 ray.get执行编译后的图。声明数据依赖DAG 节点可以传给其他.bind()调用以表达数据依赖。把同一输入传给多个 actor 形成并行扇出时使用MultiOutputNode表示图返回多个输出dag.execute()会返回多个CompiledDAGRef每个对应一个输出节点。执行顺序上有三条语义官方明确给出实践中必须理解同一 actor 内Compiled Graph 按序执行。一个 actor 在同一图中有多个任务时会对当前一次 DAG 输入的全部任务执行完毕才处理下一次输入跨 actor执行可以流水化pipelined上游 actor 可能已开始处理下一次输入而下游 actor 还在处理上一次目前仅支持 actor 任务非 actor 任务不在支持范围内。asyncio 支持如果 driver 本身跑在 asyncio 事件循环里典型如 LLM serving 框架的入口编译时传enable_asyncTrue随后使用execute_asyncawait到输入已提交即返回一个 future之后再await拿结果从而不阻塞事件循环。生命周期管理Compiled Graph 用完有两种释放方式删除对象或显式调用dag.teardown()。显式 teardown 之后参与图中的 actor 可以被复用到新的 Compiled Graph 中。从源码可以看到这一点并非空话CompiledDAG用进程级弱引用字典追踪所有编译图并在解释器关闭时统一清理——compiled_dag_node.py 中的_compiled_dagsWeakValueDictionary与_shutdown_all_compiled_dags()会由ray.worker.shutdown注册为 atexit 钩子调用逐个teardown(kill_actorsTrue)避免 actor 任务不可取消导致的关闭挂起。执行与失败语义与经典 Ray 一致Compiled Graph 把异常传播到最终输出但两类异常的处理策略不同见 quickstart 的 Execution and failure semantics应用异常任务内抛出的异常被包装为RayTaskError在 caller 对结果ray.get()时抛出该异常同时继承RayTaskError与原异常类。图在应用异常后仍可继续执行系统异常actor 死亡抛ActorDiedError网络等意外错误抛RayChannelError。图会自动关闭shut down若 actor 死亡导致关闭其余 actor 仍然存活、可复用。这些异常类型定义在 exceptions.py 中compiled_dag_node.py 的导入块RayCgraphCapacityExceeded、RayChannelError、RayChannelTimeoutError、RayTaskError完整枚举了该机制涉及的异常族。执行超时NCCL 网络错误等异常需要额外处理才不会挂死。当前 Ray 的策略是提供可配置超时作用于compiled_dag.execute()和ray.get()两处默认各 10 秒通过环境变量覆盖RAY_CGRAPH_submit_timeoutcompiled_dag.execute()的超时RAY_CGRAPH_get_timeoutray.get()的超时ray.get()也支持按调用传timeout参数。GPU 通信类型提示驱动的传输路径这是 Compiled Graph 相对经典 Ray 最有差异化的能力对应快速上手文档的 CPU to GPU communication 与 GPU to GPU communication 两节。CPU 到 GPU经典 Ray 在 actor 间传递torch.Tensor时并不知道最终设备可能出现不必要的跨设备拷贝——driver 发 CPU 张量时GPU actor 收到的仍是 CPU 副本。Compiled Graph 允许在图声明时用类型提示注解说明张量的最终设备后端会把张量拷贝到 Ray 分配给目标 GPU actor 的设备上。从源码结构看设备感知传输由ray/experimental/channel中的通道channel体系承载compiled_dag_node.py 导入的SharedMemoryType、TorchTensorType、torch_tensor_accelerator_channel含_init_communicator/_destroy_communicator、AcceleratorContext与auto_transport_typeTypeHintResolver共同构成根据类型提示选择传输介质的管线。相对手工搬运官方给出的优势是最小化拷贝次数例如一路 CPU 进多路 GPU 出时只需一次写入共享内存缓冲 每块目标 GPU 一次 host-to-device 拷贝且后续可结合内存 pinning、CPU 目的地零拷贝反序列化等技术继续优化。GPU 到 GPUNCCLCompiled Graph 支持基于 NCCL 的 CUDAtorch.Tensor传输完全绕过 Ray 的 CPU 共享内存 object store配合用户类型提示Ray 会提前准备 NCCL 通信子并排定操作调度从而避免死锁并支撑通信-计算重叠。实现底层依赖 CuPyCuPy 版本决定 NCCL 版本官方也计划支持自定义通信子如跨 CPU 的集合通信、复用已有集合组。启用方式为把承载张量的 DAG 节点用with_tensor_transport包裹该 API 的参考页即 DAGNode.with_tensor_transport示例代码见 quickstart。注意该示例至少需要 2 块 GPU。当前限制仅支持torch.Tensor NVIDIA NCCL仅支持点对点传输集合通信collective即将支持通信操作目前是同步的重叠能力属于实验特性。实验特性通信与计算重叠overlap 文档描述了当前的实验特性编译时传_overlap_gpu_communicationTrueCompiled Graph 会自动把 GPU 通信与计算操作重叠掩盖通信开销。官方示例输出不同硬件上数值会有差异overlap_gpu_communicationFalse, duration1.0670117866247892 overlap_gpu_communicationTrue, duration0.9211348341777921即该例开启后延迟约降低 14%。从源码结构看重叠调度由 compiled_dag_node.py 导入的_generate_overlapped_execution_schedule、_extract_execution_schedule等调度生成函数实现并可通过RAY_CGRAPH_VISUALIZE_SCHEDULE相关工具可视化执行调度见 compiled_dag_node.py 的常量导入。剖析与可视化性能定位工具见 profiling三套手段PyTorch Profiler运行脚本时设RAY_CGRAPH_ENABLE_TORCH_PROFILING1执行后在当前工作目录生成compiled_graph_torch_profiles目录每个 actor 一个 trace 文件RAY_CGRAPH_ENABLE_TORCH_PROFILING1 python3 example.pyNsight SystemsCompiled Graph 构建在 Ray 的 profiling 能力之上。按 Ray 文档Run Nsight on Ray一节给相关 actor 配置runtime_env后照常创建并执行图结果落在/tmp/ray/session_*/logs/{profiler_name}下。若要细看方法调用与系统开销再设RAY_CGRAPH_ENABLE_NVTX_PROFILING1它利用 NVTX 库自动为编译图执行循环中调用的所有方法打注解。图结构可视化调用CompiledDAG.visualize()编译之后默认在当前目录生成 PNG 图compiled_graph.png依赖graphviz同一 actor 的任务着色一致便于快速核对图拓扑。experimental_compile与visualize等 API 的定义分别在 dag_node.py 和 compiled_dag_node.py剖析开关常量集中在 constants.py。限制与排障必读troubleshooting 汇总了当前的硬限制直接决定你使用方式是否正确调用方限制只有编译该图的进程可以调用它。在途执行上限Compiled Graph 有最大在途执行数。经典 DAG API 在资源不足时排队而 Compiled Graph 目前不支持超出容量排队——需要先用ray.get()消费部分结果再提交更多执行作为兜底dag.execute()卡太久会抛RayCgraphCapacityExceeded。后台线程执行Compiled Graph 任务在 actor 的后台线程执行同一 actor 上的普通任务在主线程执行两者之间的同步由你负责理想情况下尽量不要在 actor 参与图时再发其他任务。一个 actor 同一时刻只能参与一个 Compiled Graph要换图必须先 teardown。CompiledDAGRef约束结果不能传给其他任务或 actor这恰恰是后端知道精确推送目标能提速的原因ray.get()对同一 ref最多调用一次因为底层结果缓冲要为下一次执行复用。零拷贝与死锁若ray.get()返回值是零拷贝反序列化典型如 NumPy 数组再次执行同一 DAG 会阻塞到该值在 Python 中离开作用域。长期持有此类结果并超并发执行时目前会以RayChannelTimeoutError表现。因此显式del掉 NumPy 数组结果并在复用同一批 actor 前显式teardown()——隐式 GC 触发的 teardown 时序不定可能导致资源冲突甚至 segfault。集合通信GPU-GPU 目前仅点对点collective 即将支持。官方同时列出路线图更好的 DAG 输入排队、更多 NCCL 集合操作、同一 actor 上多个 DAG、以及通用性能改进。运行期循环的实现可以在 compiled_dag_node.py 的do_exec_tasks中直接阅读——它作为注入 actor 的通用方法按调度表无限循环执行各_DAGNodeOperation这正是预生成调度 后台线程模型的落点。适用场景官方给出的目标用例是高性能多 GPU 工作负载具体包括 LLM 推理与分布式训练特征是需要亚毫秒级任务编排需要 GPU-GPU 点对点或集合通信异构heterogeneous或 MPMD多程序多数据执行模式。如果你正在用 Ray 搭建跨多块/多节点 GPU 的推理或训练系统且热点在高频小消息调度或跨卡张量搬运Compiled Graph 是仓库内应当优先评估的执行路径文档、示例与 API 参考分别位于 ray-core/compiled-graph 目录下的 quickstart、profiling、overlap、troubleshooting 与 API 页核心实现集中在 python/ray/dag 与 python/ray/experimental/channel可作为进一步深入源码的入口。【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考