系列文章:
Flyte工作流(Workflow)平台调研(一)——整体架构
Flyte工作流(Workflow)平台调研(二)——核心概念说明
Flyte工作流(Workflow)平台调研(三)——核心组件原理
Flyte工作流(Workflow)平台调研(四)——服务部署
Flyte工作流(Workflow)平台调研(五)——扩展集成
Flyte工作流(Workflow)平台调研(六)——跟Ray框架对比
Flyte工作流(Workflow)平台调研(七)——核心源码走读
正文:
整体说明
Flyte和Ray都是分布式计算领域的开源工具,但它们的核心目标和功能有所不同。Flyte专注于为机器学习和数据处理工作流提供编排、管理和版本控制功能,支持复杂依赖关系和任务的复现,适合整个数据和模型生命周期的管理。Ray则侧重于高性能分布式计算框架,支持快速构建分布式应用,如强化学习和大规模数据处理,提供低延迟的任务调度和弹性扩展能力。两者都支持并行计算、可扩展性和与Python的深度集成,但Flyte更强调工作流的管理和可重复性,而Ray更关注分布式计算的性能和灵活性。二者最核心的区别在于:
- Flyte是一个提供产品平台,提供了完整的工作流编排和管理的功能。主要解决工作流任务依赖、复现性、版本控制和跨团队协作等问题。它适合管理复杂的机器学习管道和数据处理工作流,强调任务的可靠性、可重复性和生命周期管理。并且强依赖K8S,其中数据层面的FlytePropeller就是扩展K8S原生Controller实现的K8S Operator,所以,最终所有的工作流任务都会在K8S集群中执行。
- Ray更像一个机器学习高性能分布式计算的执行引擎,专注于为需要大量并行计算的应用(如强化学习、分布式模型训练和实时数据处理)提供低延迟、弹性扩展和灵活任务调度的能力。并且Ray集群可以部署在物理机、虚拟机和K8S上,不是强依赖K8S的。
核心对比点:
特性 | Flyte | Ray |
---|---|---|
核心定位 | 工作流编排平台,专注于定义、调度和管理复杂的依赖关系(DAG)。 | 分布式计算框架,专注于弹性资源分配和任务执行,尤其是并行和实时任务。 |
架构 | 基于 Kubernetes,任务执行和资源调度完全依赖 Kubernetes 的能力。 | 自定义资源调度和计算引擎,提供更灵活的任务分布和实时计算能力。 |
核心组件 | 包括FlyteAdmin(负责工作流的调度和管理),FlytePropeller(执行工作流的核心引擎),DataCatalog(管理数据集和中间结果)以及FlyteConsole(提供用户友好的Web界面)。 | 由Ray Core(基本分布式能力)、Ray Data(数据处理)、Ray Train(训练)、Ray Tune(超参数调整)、Ray Serve(推理)、Ray RLlib(强化学习)以及Ray AIR(上层机器学习API)等模块组成。 |
任务模型 | 强调任务的依赖关系,使用 DAG 定义工作流。支持复杂的嵌套和分支逻辑。 | 强调无依赖的并行任务,适合需要高频通信的实时计算,如分布式训练或实时分析。 |
生态集成 | 与 ML/数据工具(如 PyTorch、TensorFlow、Spark、Hive)紧密集成,适合机器学习管道。 | 提供内置的分布式训练(Ray Train)、数据处理(Ray Data)和强化学习(RLlib)功能,适合 ML 和实时分析任务。 |
资源调度 | 由 Kubernetes 控制,提供一致性和可预测性,但需要 Kubernetes 的支持。 | 内置的分布式调度器,支持动态扩展 Ray 集群,甚至在无 Kubernetes 的环境中运行。 |
实时性 | 偏向批处理和依赖清晰的工作流,不适合实时高频通信任务。 | 支持低延迟的实时任务,尤其适合需要频繁交互的任务,如分布式强化学习或并行模拟。 |
适用场景 | 适合 ML 工作流、ETL 管道、跨任务依赖复杂的 DAG 执行(如数据科学工作流)。 | 适合分布式训练、高性能计算(HPC)、实时数据流处理和高并发任务。 |
部署架构对比
Flyte部署架构
Flyte整体的部署架构如下图所示:
用户层面的工具,用户通过自己的资源使用。服务层面,主要分为控制层面(Control Plane)和数据层面(DataPlane)。其中:
1. 控制层面主要就是FlyteAdmin,这是Flyte系统中一个关键的集中点,在生产环境中,为了保证其可用性和故障恢复能力,通常会采用一些常见的架构模式,如:
- 高可用性(HA)配置:通过Kubernetes等容器编排工具,可以配置多个FlyteAdmin实例,并配合负载均衡器来实现高可用性。在这种配置下,即使单个实例失败,系统仍能继续运行。
- 数据持久化:FlyteAdmin依赖的外部数据库通常支持分布式和复制配置,以保证数据的安全和系统的鲁棒性。
虽然FlyteAdmin本身设计上不支持以分布式的模式运行,但通过其部署和依赖组件的架构设计,可以在一定程度上实现分布式的优点,如高可用性和数据的持久化。
2. 数据层面包括FlytePropeller以及工作流执行的CRD和运行节点(Pod)。
- FlytePropeller本来就是K8S原生的Operator,只能依赖K8S部署
- 工作流运行节点都是基于CRD,通过FlytePropeller启动的K8S Pod
所以,数据层面原生依赖K8S集群,不能脱离K8S集群实现。但一个FlyteAdmin可以向多个K8S集群发送工作流任务,每个K8S集群中都有一个FlytePropeller。
Ray部署架构
Ray的整体部署架构如下图所示:
Ray的给用户提供SDK编写工作流任务,也提供Ray Client远程向Ray Cluster服务提交工作流任务。
Ray Cluster包括一个Head Node多个Worker Node,Ray Cluster可以部署在云虚拟机、K8S集群或者本地的物理机上。
总结
1. Flyte服务部署分为控制面和数据面:
- 控制面FlyteAdmin,是一个单点服务,但是可以通过HA或者持久化提高可用性。可以部署在K8S、云虚拟机或者本地物理机上。(这个服务比较像一个服务的业务后端)
- 数据面的FlytePropeller是原生的K8S Operator,只能依赖K8S集群,然后在K8S集群中执行工作流任务。但是一个FlyteAdmin可以支持多个FlytePropeller,也就是FlyteAdmin的工作流任务可以提交到多个K8S集群中执行。(这个服务是真正执行和调度工作流的)
2. Ray是一个典型的集群部署的架构,Ray Cluster分为Head Node和Worker Node,可以部署在K8S、云虚拟机或者本地物理机上。
注意:一个Ray Cluster中,只有一个Head Node。不过可以通过KubeRay在K8S集群中多部署几个Ray Cluster。
功能对比
Flyte的主要功能
Flyte是一个开源的、可扩展的工作流编排平台,专门设计用于数据科学和机器学习工作流程,使用户能够更容易地创建、扩展和管理这些流程。以下是Flyte的主要功能概述:
- 高度可扩展性:Flyte能够处理各种规模的工作负载,从小型项目到大型企业级应用,确保了平台的可扩展性。
- 灵活性和多语言支持:Flyte支持多种编程语言和框架,使得它能够适应不同的技术栈和业务需求。
- 统一平台:Flyte提供了一个统一的界面,将数据处理、机器学习和分析任务整合在一起,简化了工作流程的管理。
- 版本控制和可重现性:平台确保工作流程可以被精确地重现和追踪,有助于管理和控制项目变更。
- 强大的调度和资源管理:Flyte优化资源利用,提供强大的调度功能,以提高工作效率。
- 多租户支持和安全性:作为一个托管、多租户的服务,Flyte支持在隔离的环境中独自部署和扩展工作,同时确保了代码执行的可重复性。
- 弹性规模:Flyte的设计支持弹性扩展,可以在多个集群、数千个节点和数千个并发工作流上运行,满足了不同规模需求。
- 声明式API:Flyte通过提供一个声明式的API来定义工作流程,简化了数据处理和机器学习任务的描述。
Flyte工作流平台的目标是通过抽象底层复杂性,提高机器学习和数据处理任务的开发速度,使团队能够更专注于业务逻辑而非基础设施。
Ray的主要功能
Ray是一个高性能、开源的分布式计算框架,旨在简化并行和分布式应用程序的编写。Ray的主要功能包括:
- 并行任务执行: Ray允许开发者将任务并行地执行在多个节点上,从而提高处理效率和速度。通过
@ray.remote
装饰器定义可在远程执行的函数。 - 分布式对象存储: Ray提供了分布式对象存储功能,允许在不同节点之间共享数据,并在任务之间传递大规模的数据。
- 弹性资源调度: Ray可以根据任务需求动态分配和释放资源,提高资源利用率和性能。
- Actor模型: Ray支持Actor编程模型,允许开发者定义有状态的计算实体(Actors),这些Actors可以响应来自其他任务的消息。
- Ray Tune: 一个用于超参数调整的库,可以自动优化机器学习模型的参数。
- Ray RLlib: 用于强化学习的库,支持大规模的强化学习工作负载。
- Ray Train: 提供了简单的接口来启动分布式机器学习训练任务。
- Ray Serve: 用于构建和部署可扩展的机器学习服务。
- Ray AIR: 包含了构建机器学习流程的上层API,例如训练循环的抽象。
- 分布式追踪和调试: Ray提供了工具来监控和调试分布式应用的性能。
- 可扩展性和容错性: Ray的架构设计使其具有高度的可扩展性和容错性,支持在多个集群和节点上运行。
- 对GPU/CPU资源的有效管理: Ray可以管理并分配GPU和CPU资源给不同的任务和应用程序。
- 提供分布式任务工作流能力:Ray Workflow,可以把任务编写为工作流方式,并提供工作流持久化存储能力。
Ray的设计理念是提供高性能的分布式计算能力,同时保持接口的用户友好性和编程模型的简洁性,主要是为了处理大规模机器学习和数据处理任务。
总结
Flyte和Ray是两个面向不同需求的开源工具,他们功能有部分相同,但是核心的目标和设计理念不同,下面是总结的功能对比:
相同点:
- 分布式计算:Flyte和Ray都支持分布式计算,可以跨多个节点执行任务,提高处理效率。
- 可扩展性:二者都设计有良好的可扩展性,可以根据任务需求动态调整计算资源。
- 容器化支持:Flyte和Ray都支持容器化技术,如Docker,确保任务在任何环境中都能以相同的方式运行。
不同点:
- 主要目标:
- Flyte:专注于数据科学和机器学习工作流的编排和执行。它提供了一个统一的平台上管理数据处理、机器学习和分析任务。
- Ray:是一个通用分布式应用程序的框架,支持构建和运行分布式应用,尤其擅长处理Python中的并行和分布式计算问题。
- 设计理念:
- Flyte:提供了一个声明式的API来定义工作流程,并关注于版本控制、可重现性和工作流的可管理性。
- Ray:提供了弹性资源调度和多任务并行执行的框架,强调快速开发和运行分布式代码。
使用方式对比
Flyte的使用方式
Flyte是一个工作流管理平台,主要的使用是围绕工作流进行:
1. 定义工作流
- 使用Flytekit:本地安装Flytekit,然后在Python中使用Flytekit来定义任务和工作流。Flytekit提供了编程接口来创建任务(可执行的基本单元),并通过依赖关系定义这些任务如何组成工作流。
import pandas as pd
from sklearn.datasets import load_wine
from sklearn.linear_model import LogisticRegression
from flytekit import task, workflow
from flytekit.types.pickle import FlytePickle
# @task decorators define the building blocks of your pipeline
@task
def get_data() -> pd.DataFrame:
"""Get the wine dataset."""
return load_wine(as_frame=True).frame
@task
def process_data(data: pd.DataFrame) -> pd.DataFrame:
"""Simplify the task from a 3-class to a binary classification problem."""
return data.assign(target=lambda x: x["target"].where(x["target"] == 0, 1))
@task
def train_model(data: pd.DataFrame) -> FlytePickle:
"""Train a model on the wine dataset."""
features = data.drop("target", axis="columns")
target = data["target"]
return LogisticRegression(max_iter=1000).fit(features, target)
# @workflows decorators define the flow of data through the tasks
@workflow
def training_workflow() -> FlytePickle:
"""Put all of the steps together into a single workflow."""
data = get_data()
processed_data = process_data(data=data)
return train_model(data=processed_data)
if __name__ == "__main__":
# You can run this script with pre-defined arguments with `python flyte_workflow.py`
# but we recommend running it with the `pyflyte run` CLI command, as you'll see in
# the next step of this walkthrough.
print(f"Running training_workflow() {training_workflow()}")
- 声明式API:Flyte使用声明式API来定义工作流,其中包含了一组任务、每个任务的输入输出、以及任务间的依赖关系。
2. 执行工作流
- 本地执行:Flyte工作流可以在本地进行测试和执行,确保逻辑正确。前提是本地安装了工作流执行的必要的库。
pyflyte run flyte_demo/workflows/flyte_workflow.py training_workflow
- 在远程执行:对于大规模的工作流,需要使用Flytectl提交到远程的Flyte平台上,先提交到FlyteAdmin中,记录、保存工作流,并将工作流转换为在K8S中执行的CRD。然后通过K8S Client提交到FlytePropeller,有FlytePropeller创建工作流任务的节点(Pod),然后执行工作流。
pyflyte run --remote flyte_demo/workflows/flyte_workflow.py training_workflow
3. 监控和管理工作流
- Flyte Console:Flyte提供了一个Web界面,用于监控工作流执行的状态、查看执行历史和性能指标等。
- Flyte CoPilot:一个辅助工具,帮助智能地管理和监视工作流的输入输出数据。
Ray的使用方式
Ray主要用于分布式计算,能够跨多台机器执行任务,从而提升运行速度和效率。使用Ray或者Ray Client能够提交Task(任务)、Actor或者Workflow。下面是详细的使用方式:
使用Ray提交远程任务
1. 初始化Ray:在初始化访问Ray,使用ray.init()
。如果是在一个集群环境中,需要适当配置以确保可以访问集群中的资源。传入的是Ray集群的地址,比如:
ray.init(address="auto") # 如果本机上安装了Ray的主节点,就可以这样初始化
# ray.init(address="ray://{ray cluster ip}:10001") # 初始化远程连接Ray
2. 定义远程任务:使用@ray.remote
装饰器定义可在Ray集群中远程执行的函数。
@ray.remote
def my_task(x, y):
return x + y
3. 执行远程任务:通过调用远程函数并使用ray.get()
获取结果。
result = my_task.remote(1, 2)
print(ray.get(result))
使用Ray提交远程Actor
1. 初始化Ray
2. 定义Actor:与远程任务相似,使用@ray.remote
定义一个类作为Actor。
@ray.remote
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
return self.count
3. 创建和调用Actor:实例化Actor并调用其方法。
counter = Counter.remote()
result = counter.increment.remote()
print(ray.get(result))
使用Ray提交Workflow
1. 如果要使用Ray的Workflow,Ray启动的时候,要指定存储(--storage)参数,比如:
ray start --head --port=6379 --storage=local:D:/ray_workflow_data
因为workflow的元数据需要持久化存储,存储后的Workflow元数据为:
注意:后面会专门写一篇博客,介绍Ray的Workflow。
2. 定义Workflow:需要先定义远程任务,然后再用bind方法组装成工作流
@ray.remote
def one() -> int:
return 1
@ray.remote
def add(a: int, b: int) -> int:
return a + b
dag = add.bind(100, one.bind())
3. 运行工作流:运行时,可以指定工作流的唯一workflow_id。可以同步提交,也可以异步提交,并且可以查看工作流的元数据和状态。
workflow.run(dag, workflow_id="run_1") # 同步提交
workflow.run_async(dag, workflow_id="run_1") # 异步提交
workflow.get_status("run_1") # 获取工作流的状态
workflow.get_output("run_1") # 获取工作流的输出结果
使用场景对比
Ray的使用场景
- 分布式计算:Ray设计用于分布式应用程序的运行,特别是那些需要大规模并行处理的任务。它支持从小型项目到大规模企业级应用的各种工作负载。
- 机器学习和深度学习:Ray提供了一整套工具和API,支持从训练到部署的全过程,适用于复杂的分布式计算任务,如批量推断、多模型训练、模型服务、超参数调优、分布式训练、强化学习等。
- 灵活性和多语言支持:Ray支持多种编程语言和框架,使得它能够适应不同的技术栈和业务需求。
Flyte的使用场景:
- 数据处理和机器学习工作流编排:Flyte专注于数据科学和机器学习工作流的编排和执行,提供了一个统一的平台来管理数据处理、机器学习和分析任务。
- 可扩展性和企业级应用:Flyte设计理念是为用户提供一个无缝的、灵活的工作流管理体验。它能够处理从小型项目到大规模企业级应用的各种工作负载。
- 版本控制和可重现性:Flyte确保工作流程可以被精确地重现和追踪,这对于数据处理和机器学习实验尤其重要。
- 生产级数据和ML管道:Flyte旨在构建生产级的数据和机器学习管道,支持分布式执行和高效的资源利用。
对比和总结
- 适用领域:Ray更适合需要高度并行处理和灵活多语言支持的分布式计算场景,而Flyte更适合于需要严格工作流编排和管理的生产级数据处理和机器学习场景。
- 设计理念:Ray注重快速开发和执行分布式代码,Flyte强调工作流的编排、管理、可重现性和企业级应用。
- 功能特性:Ray提供了强大的分布式计算和机器学习功能,如分布式训练、超参数调优等;而Flyte提供了工作流的定义、执行、监控以及数据管理的全套功能。 选择使用Ray或Flyte应基于特定需求、团队的技术栈偏好以及对工作流管理的需要。