#部署 #分布式 #架构

nightly bin+lib deploy

deploy 库帮助编写和调试分布式程序,以及跨集群运行它们的工具

1 个不稳定版本

使用旧的 Rust 2015

0.1.3 2018年8月15日
0.1.2 2018年6月27日
0.1.1 2018年6月26日
0.1.0 2018年6月24日

580并发 中排名 #580

Download history 22/week @ 2024-03-29 5/week @ 2024-04-05

10,437 每月下载量

Apache-2.0

255KB
7.5K SLoC

deploy

Crates.io Apache-2.0 licensed Build Status

文档

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();
}

Screencap of deploy being used

Deploy 有两个组件

  • 一个函数库,使您能够 spawn() 进程,以及 send()recv() 之间的通信
  • 当您想要在多个服务器上运行时,一个分布式执行架构,以及添加到 cargo 中的 deploy 命令,用于将程序部署到该架构上。

两者都像上面一样输出到命令行 - 唯一的区别是后者已通过网络转发。

Deploy 仍处于初期阶段 - 正在进行开发和测试,以支持 macOS 和 Windows(目前仅限 Linux)并达到足够成熟的水平,适用于生产使用。

目前的主要工作是测试、文档、改进 API(特别是错误信息和 select() 的可用性),以及移植到 macOS 和 Windows。

功能

Deploy 负责以下内容

  • spawn() 将具有定义的内存和 CPU 资源需求的进程分布到具有可用资源的服务器上
  • 尽力而为地强制执行这些内存和资源需求,以避免有缺陷的/贪婪的进程饿死其他进程
  • 通过 TCP 在进程之间建立通道,具有自动设置和删除
  • 异步(反)序列化通过通道发送/接收的值(利用 serdelibfringe
  • select() 选择通道的可接收性/可发送性
  • futures 集成,因此兼容 tokio
  • 由一个运行高效边缘触发 epoll 循环的后台线程提供动力
  • 确保在进程退出之前发送并确认数据,以避免连接重置和数据丢失(利用 atexitTIOCOUTQ
  • 地址:所有通道都在集群范围内的 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 deployments,此时它使用特殊的环境变量来运行二进制文件,以触发 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

参见Rust文档

测试

参见TESTING.md

为什么

部署是我正在进行的规模数据项目的基础。我决定开始对其进行润色,并作为开源发布,以防它可能对其他人有趣或有用!

许可证

根据Apache License,版本2.0许可(LICENSE.txthttps://apache.ac.cn/licenses/LICENSE-2.0)。

除非您明确说明,否则您有意提交的任何贡献,根据Apache-2.0许可证的定义,应按照上述方式许可,不附加任何额外条款或条件。

依赖项

~10MB
~187K SLoC