0x、写在前头
以下内容来自reddit 社区(Distributed computing in Rust, https://www.reddit.com/r/rust/comments/155hxlf/distributed_computing_in_rust/),由小编重新整理后发布,读起来也许会更流畅些,因为在整理过程中,会揉一些小遍的思考进去,感兴趣的小伙伴,可以在读完本文后,去读读原文,链接在上方。因为是边看reddit,边译边写边思考,可能行文会有些乱。见谅!
小编在逛 reddit 社区的时候,看到一篇帖子Distributed computing in Rust”,就忍不住点进去,才发现是一个长帖,很吸引人。
一、先说问题
一名叫 amindiro 的老哥提了一个问题,小编分两段来介绍下:
他说自己是一名机器学习工程师,最近开始学习 Rust,他很喜欢Rust! 他认为 Rust 将是一种编写数据处理工具的出色语言,并且可以取代现有的库(通常用 Python 或带有 Python wrapper的 C 语言编写)。大规模数据处理通常意味着分布式并行计算。像 dask 和 ray 这样的库是令人惊叹的库,您可以在其中动态地在正在运行的集群上分派函数。 Dask(注:Dask 是一个灵活的 Python 并行计算库) 完全用 Python 编写,通过序列化 Python 函数并使用 TCP 将它们发送到在本地线程池中运行它们的工作进程来解决这个问题。 Ray (注:Ray 是一个开源统一计算框架,可以轻松扩展 AI 和 Python 工作负载)是用 C++ 编写的并且做了同样的事情。
他的问题是,这个叫 amindiro 老哥想使用 Rust 在运行时实现相同的行为,像 serde_closure
这样的包用于序列化闭包(serialize closure)并通过网络发送它们。然后他提到这样做有一个问题,就是客户端进程和工作进程的二进制文件要是相同的(注:对,这是这个方法的限制,因为闭包的序列化和反序列化需要在两端使用相同的闭包类型,不知道这样说对不对)。紧接着,这个叫 amindiro 老哥他说,用这个方法的缺点是不能在集群中生成并发送任意的Rust函数给正在运行的进程(can't spawn a cluster and send arbitrary rust functions to the running processes)。
小遍尝试去理解他的问题:1. 我有机器学习的基础,对传统(这里定义成使用非Rust工具)大规模数据处理我还比较行;2. 因为这里没有提到会不会C++,假设我不会。3. 我还在学习Rust,假设我Rust学的还行,但不是专家级,能用能写小东西。4. 我想使用Rust实现在运行时动态传递函数的行为,并且我要面向的场景是集群(cluster),我该怎么办?
省流版描述:如何使用Rust做分布式计算集群中的大规模数据处理工作?
二更问题:如何使用Rust实现一个灵活、高效的分布式计算框架,重点是可以调度任意函数并支持Actor模型,从而可以更方便地进行分布式计算和处理大规模的任务。
二、再说回答
第一种讨论是,在分布式节点中,可以考虑让 WASM模块 与本机计算库交互,但是如果需要高性能和高效率,就需要评估Wasm和本机代码之间的差异了。但是这样做有一个问题,WASM 的当前标准是 32 位,64 位版本仍处于提案阶段(注:https://webassembly.github.io/spec/core/bikeshed/,Future versions of WebAssembly might provide memory instructions with 64 bit address ranges. 其实还有一点,wasm貌似不支持cuda,因为不太懂wasm以及wasm是否有gpu提案这样,这里纯属臆想,欢迎评论区吹水)。因此,这对于处理大型数据集,可能是一个问题。
第二种方讨论说是,在 noir(分布式流处理框架)中,使用类似 mpirun 的方法,通过使用 SSH 来分发二进制文件并开始计算。可以研究使用 wasm 运行时来生成和编排分布式应用程序,这似乎是可行的 (注:其实关于使用wasm后与原生相比,性能损失有多少,是一个需要研究的话题)。
第三种讨论是,关注 Ray C++,成立一个社区,去推Rust 分布式计算这件事(start a community driven Rust distributed computing project)。
第四种讨论是,如果集群节点够大,可以尝试使用GNU Parallel和Rust相结合的方法,这可以绕开序列化 Rust 函数(instead of serializing a Rust function),从而实现通过网络发送二进制文件和环境变量。
第五种讨论是,有小伙伴提到 Apache Arrow Ballista(https://github.com/apache/arrow-ballista/), 但是amindiro 老哥更想的是一个更加通用的使用Rust实现的分布式计算框架(a more general distributed computing framework using Rust)。
第六种讨论是,有小伙伴提到Arroyo (https://github.com/ArroyoSystems/Arroyo),这是一个分布式流处理引擎,但是amindiro 老哥提到,如果实例超参数调整工作流程或某些 RL 工作流程,Arroyo会很难实现(For instance Hyper parameter tuning workflow or some RL workflows can be tricky to implement this way)。
第七种讨论是,“我想使用Rust实现在运行时动态传递函数的行为,并且我要面向的场景是集群(cluster),我该怎么办?”,针对这个问题,可以使用使用 Nextflow(https://www.nextflow.io/) 来进行编排计算执行,amindiro 老哥说他想做的是separate running cluster,所以这里也不行((注:但是,这个方法应该更适用于Batch Job Workflow,针对实时的Separate Running Cluster,这是两种不同的工作流性质和执行方式)。
第八种讨论是,elixir + rust nifs。(注:字少事大,感觉很硬的技术栈,不懂)
第九种讨论是,使用dll,但是做runtime linking很难。(注:这里简译了,因为不太懂,可以看看:https://www.reddit.com/r/rust/comments/155hxlf/comment/jsw1wfq/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button)
第九种讨论是,有小伙伴说, 可以使用nvidia 的 NCLL 来做分布式编程。dask 使用自定义 rpc 协议进行分布式计算。至于 GPU 集群,他认为 nvidia 有 NCLL,这是实现分布式编程的两种不同方法。但是amindiro 老哥说,“Dask RPC 协议基本上是调用 cloudpickle 来序列化 python 函数并通过 TCP 发送它们。当使用编译语言时,这是一个棘手的部分,函数序列化在 Rust 中并不那么简单……NCLL 遵循 MPI 接口,使用起来可能很棘手。在 MPI 中进行分布式计算是可行的替代方案,但无法解决所需的动态问题”。
第十种讨论是,提到r-link,一种Flink替代方案。但是,amindiro 老哥更关注的是能够在分布式环境中调度和执行任意函数(being able to schedule arbitrary functions and support some kind of Actor model to have distributed state)(注:能够将函数发送到不同的节点,让它们在各自的本地环境中运行,并收集结果,灵活。)。
第十一种讨论是,使用Daft Dataframe library,但是Daft 依赖于Ray。显然,amindiro 老哥想要的不是这个,他的想法更宏大。
第十一种讨论是,使用 Lunatic。(注:Lunatic是一个runtime,可以简单理解为:Erlang / Elixir BEAM+WASM+Rust=Lunatic )
三、写在最后
以上回答部分,对原帖对一些回答进行了摘录、整理和注释。看完这个帖子,感觉这真的是一个好问题,欢迎大家在下方留言讨论,或在群内吹水。
大家的办法是什么呢?
From 日报小组 Lambert
社区学习交流平台订阅:
评论区
写评论勘误勘误!!!经公号一小伙伴留言提醒,文中有一个地方打错了,不是Nvidia ncll,是 NCCL (NVIDIA Collective Communications Library)。
hhh🐮的
--
👇
Nayaka: elixir + nifs
elixir + nifs