1 个不稳定版本
使用旧的 Rust 2015
0.1.3 | 2018年8月15日 |
---|---|
0.1.2 |
|
0.1.1 |
|
0.1.0 |
|
580 在 并发 中排名 #580
10,437 每月下载量
255KB
7.5K SLoC
deploy
Deploy 是 Rust (nightly) 的运行时环境,帮助编写、调试和部署分布式程序。以下是一个这样的程序示例
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate deploy;
use deploy::*;
fn main() {
init(Resources::default());
let mut total = 0;
for index in 0..10 {
let greeting = format!("hello worker {}!", index);
let worker_arg = WorkerArg{index,greeting};
let pid = spawn(worker, worker_arg, Resources::default()).expect("Out of resources!");
let receiver = Receiver::<usize>::new(pid);
total += receiver.recv().unwrap();
}
println!("total {}!", total);
}
#[derive(Serialize,Deserialize)]
struct WorkerArg {
index: usize,
greeting: String
}
fn worker(parent: Pid, worker_arg: WorkerArg) {
println!("{}", worker_arg.greeting);
let sender = Sender::<usize>::new(parent);
sender.send(worker_arg.index*100).unwrap();
}
Deploy 有两个组件
- 一个函数库,使您能够
spawn()
进程,以及send()
和recv()
之间的通信 - 当您想要在多个服务器上运行时,一个分布式执行架构,以及添加到 cargo 中的
deploy
命令,用于将程序部署到该架构上。
两者都像上面一样输出到命令行 - 唯一的区别是后者已通过网络转发。
Deploy 仍处于初期阶段 - 正在进行开发和测试,以支持 macOS 和 Windows(目前仅限 Linux)并达到足够成熟的水平,适用于生产使用。
目前的主要工作是测试、文档、改进 API(特别是错误信息和 select()
的可用性),以及移植到 macOS 和 Windows。
功能
Deploy 负责以下内容
spawn()
将具有定义的内存和 CPU 资源需求的进程分布到具有可用资源的服务器上- 尽力而为地强制执行这些内存和资源需求,以避免有缺陷的/贪婪的进程饿死其他进程
- 通过 TCP 在进程之间建立通道,具有自动设置和删除
- 异步(反)序列化通过通道发送/接收的值(利用
serde
和libfringe
) select()
选择通道的可接收性/可发送性- 与
futures
集成,因此兼容tokio
- 由一个运行高效边缘触发 epoll 循环的后台线程提供动力
- 确保在进程退出之前发送并确认数据,以避免连接重置和数据丢失(利用
atexit
和TIOCOUTQ
) - 地址:所有通道都在集群范围内的
Pid
之间,而不是(ip,port)
上 - 性能:设计用于在底层操作系统之上带来最小的开销
这是为了什么
Deploy 使编写分布式程序变得容易。类似于 MPI,它抽象出了伯克利套接字,让您能够专注于业务逻辑,而不是地址、连接、多路复用、异步、事件和终止。与 MPI 不同,它有一个理智、现代、简洁的接口,使用 serde
处理(反)序列化,提供了强大的异步构建块如 select()
,并与 tokio
等框架集成。
它是如何工作的
有两种执行模式:使用 cargo run
正常运行和使用 cargo deploy
将其部署到集群中。我们将讨论第一种,然后介绍第二种的不同之处。
每个进程都有一个 监控进程,它捕获进程的输出,并对其调用 waitpid
来捕获退出状态(无论是退出代码还是信号)。这是通过在进程初始化时进行分叉来设置的,父进程是监控进程,而子进程继续运行用户的程序。它通过将文件描述符 0、1、2(分别对应于 stdin、stdout 和 stderr)替换为管道来捕获输出,这样当用户的进程写入例如 fd 1 时,它实际上是写入一个管道,而监控进程则从该管道读取并将输出转发到 桥梁。
桥梁 是收集来自各种 监控进程 的输出并将其格式化输出到终端的工具。它是在 init()
中启动的,进程通过分叉,使得父进程成为桥梁,而子进程继续运行用户的程序。
启动
spawn()
函数接受一个函数、一个参数和资源限制,并用它们启动一个新进程。这是通过调用当前二进制的干净副本来实现的,使用 execve("/proc/self/exe",argv,envp)
,它在调用 init()
时略有不同:它会连接回现有的网桥,而不是返回控制流,而是在退出之前调用指定的用户函数。函数指针相对于文本段中的固定基址进行调整。
通过创建 Sender<T>
和 Receiver<T>
来进行通信。创建需要 Pid
,并在幕后进行大量的记账工作,以确保
- 双工 TCP 连接被正确和适时地创建和销毁,以支持用户创建的单工通道。
- TCP 连接在操作系统中的资源消耗与用户持有的通道数量成比例。
Pid
是唯一的。- 每个进程有一个唯一的端口(在初始化时临时绑定,以避免饥饿或失败),所有通道支持的 TCP 连接都通过或来自该端口。
- 序列化和反序列化可以异步发生,即如果套接字尚未准备好写入,则为了避免为 serde 的序列化结果分配无界内存,利用
libfringe
中的协程。 - 可以通过删除和重新创建通道来更改通道消息的类型。
部署
在 fabric 集群上运行时,有四个主要区别
Fabric监听可配置的地址,接收二进制文件并执行它们。
Fabric 主节点接受零个或多个其他 fabric 实例的地址和资源作为输入,以及要自动启动哪些进程 - 这几乎总是 bridge。
它监听可配置的地址,以接收具有资源需求的二进制文件以进行部署 - 但几乎总是只有当 bridge 给它这些二进制文件时才有意义。
桥梁它不是由用户进程内部的 fork 调用启动的,而是在 fabric 主节点初始化时自动启动。它监听可配置的地址以接收 cargo deploy
ments,此时它使用特殊的环境变量来运行二进制文件,以触发 init()
打印初始进程的资源需求并退出,然后将确定资源需求的二进制文件发送到 fabric master。成功分配后,它由一个 fabric 实例执行。在 init()
内部,它会连接回 bridge,桥会尽职尽责地将输出转发到 cargo deploy
。
cargodeploy
这是一个添加到cargo中的命令 (参见文档),在底层调用 cargo run
,但与本地运行生成的二进制文件不同,它会被发送到 网桥。然后,网桥 会发送回任何输出,该输出在终端上以格式化的方式显示。
如何使用
[dependencies]
deploy = "0.1.2"
extern crate deploy;
use deploy::*;
fn main() {
init(Resources::default());
println!("Hello, world!");
}
$ cargo +nightly-2018-06-10 run
3fecd01:
Hello, world!
exited: 0
或者,运行分布式:机器2
cargo +nightly-2018-06-10 install fabric
fabric 10.0.0.2:9999
机器3
cargo +nightly-2018-06-10 install fabric
fabric 10.0.0.3:9999
机器1
cargo +nightly-2018-06-10 install fabric deploy
fabric master 10.0.0.1:9999 400GiB 34 bridge 10.0.0.1:8888 \
10.0.0.2:9999 400GiB 34 \
10.0.0.3:9999 400GiB 34
您的笔记本电脑
cargo +nightly-2018-06-10 install deploy
rustup default nightly-2018-06-10 # cargo deploy doesn't support +version syntax yet
cargo deploy 10.0.0.1:8888 --release
833d3de:
Hello, world!
exited: 0
要求Rust:nightly。 注意:当前的nightly rustc 崩溃,所以暂时使用已知的可工作的 nightly-2018-06-10
。
Linux:内核 >= 3.9;/proc
文件系统;IPv4,其中提供给fabric主机的地址可以被fabric自身绑定(这个要求可能被放宽)。
Arch:x86-64(这个要求可以相当直接地扩展到libfringe支持的x86、x86_64、aarch64、or1k)。
如果您遇到其他要求,请提交问题。
API
测试
为什么
部署是我正在进行的规模数据项目的基础。我决定开始对其进行润色,并作为开源发布,以防它可能对其他人有趣或有用!
许可证
根据Apache License,版本2.0许可(LICENSE.txt 或 https://apache.ac.cn/licenses/LICENSE-2.0)。
除非您明确说明,否则您有意提交的任何贡献,根据Apache-2.0许可证的定义,应按照上述方式许可,不附加任何额外条款或条件。
依赖项
~10MB
~187K SLoC