Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

分布式部署指南

Adora 支持跨多台机器部署数据流,用于多机器人车队、边缘 AI 流水线和分布式机器人系统。本指南涵盖集群管理、节点调度、二进制分发、自动恢复和运维最佳实践。

目录


概述

Adora 的分布式架构有三个层级:

CLI  -->  Coordinator  -->  Daemon(s)  -->  Nodes / Operators
              (one)          (per machine)     (user code)
  • CLI 向协调器发送控制命令(构建、启动、停止)。
  • 协调器编排守护进程、解析节点放置、管理数据流生命周期。
  • 守护进程在每台机器上运行,生成和监控节点进程。
  • 节点通过共享内存(同一机器)或 Zenoh 发布/订阅(跨机器)通信。

分布式部署有两种路径:

临时部署 —— 在每台机器上手动启动 adora daemon,然后使用协调器进行控制。适合开发和测试。参见 CLI 参考中的分布式部署

托管部署 (cluster.yml) —— 在 YAML 文件中定义集群拓扑,然后使用 adora cluster 命令进行基于 SSH 的生命周期管理。本指南重点介绍托管路径。


快速开始

  1. 创建 cluster.yml
coordinator:
  addr: 10.0.0.1
machines:
  - id: robot
    host: 10.0.0.2
    user: ubuntu
  - id: gpu-server
    host: 10.0.0.3
    user: ubuntu
  1. 启动集群:
adora cluster up cluster.yml
  1. 启动数据流:
adora start dataflow.yml --name my-app --attach
  1. 检查集群健康状态:
adora cluster status
  1. 关闭:
adora cluster down

功能一览

特性命令 / 配置描述
集群生命周期adora cluster up/status/down从单台机器进行基于 SSH 的守护进程管理
标签调度_unstable_deploy.labels通过键值标签将节点路由到守护进程
二进制分发_unstable_deploy.distributelocal、scp 或 http 策略
systemd 服务adora cluster install/uninstall可在重启后存活的持久化守护进程服务
Auto-recoveryAutomatic守护进程重新连接时重新生成节点
滚动升级adora cluster upgradeSCP 二进制文件 + 逐台机器顺序重启
数据流重启adora cluster restart按名称或 UUID 重启运行中的数据流

集群配置参考

cluster.yml 文件定义协调器地址和集群中的机器集合。

完整模式

coordinator:
  addr: 10.0.0.1            # IP address the coordinator binds to (required)
  port: 6013                 # WebSocket port (default: 6013)

machines:
  - id: edge-01              # 唯一机器标识符(必填)
    host: 10.0.0.2           # SSH-reachable hostname or IP (required)
    user: ubuntu              # SSH 用户(可选,默认为当前用户)
    labels:                   # Key-value labels for scheduling (optional)
      gpu: "true"
      arch: arm64

  - id: edge-02
    host: 10.0.0.3
    labels:
      arch: arm64

字段

coordinator

Field类型默认描述
addrIP 地址(required)协调器绑定的地址
portu166013WebSocket 端口

machines[]

Field类型默认描述
idstring(required)唯一机器标识符,用于 _unstable_deploy.machine
hoststring(required)可通过 SSH 访问的主机名或 IP 地址
userstring当前用户SSH 用户名
labelsmapempty用于基于标签调度的键值对

验证规则

  • 至少必须定义一台机器。
  • 机器 ID 必须非空且唯一。
  • 机器主机名必须非空。
  • 未知字段会被拒绝(deny_unknown_fields)。

示例:3 机器 GPU 集群

coordinator:
  addr: 192.168.1.1

machines:
  - id: coordinator-host
    host: 192.168.1.1
    labels:
      role: control

  - id: gpu-a100
    host: 192.168.1.10
    user: ml
    labels:
      gpu: a100
      arch: x86_64

  - id: jetson-01
    host: 192.168.1.20
    user: nvidia
    labels:
      gpu: jetson
      arch: arm64

集群命令参考

所有 adora cluster 命令都基于 cluster.yml 文件操作,并使用 SSH 管理远程机器。

使用的 SSH 选项:BatchMode=yesConnectTimeout=10StrictHostKeyChecking=accept-new

adora cluster up

从 cluster.yml 文件启动多机器集群。在本地启动协调器,然后通过 SSH 登录每台机器启动守护进程。

adora cluster up <PATH>

Arguments:

Argument描述
PATH集群配置文件的路径

Behavior:

  1. 加载并验证集群配置。
  2. 在本地 addr:port 上启动协调器。
  3. 对每台机器,通过 SSH 登录并运行 nohup adora daemon --machine-id <id> --coordinator-addr <addr> --coordinator-port <port> [--labels k1=v1,k2=v2] --quiet
  4. 轮询直到所有预期的守护进程注册到协调器(30 秒超时)。

Example:

$ adora cluster up cluster.yml
Starting coordinator on 10.0.0.1:6013...
Starting daemon on robot (ubuntu@10.0.0.2)... OK
Starting daemon on gpu-server (ubuntu@10.0.0.3)... OK
All 2 daemons connected.

adora cluster status

显示集群的当前状态。展示已连接的守护进程和活跃数据流数量。

adora cluster status [--coordinator-addr ADDR] [--coordinator-port PORT]

Flags:

标志默认描述
--coordinator-addrlocalhost协调器主机名或 IP
--coordinator-port6013协调器 WebSocket 端口

Example:

$ adora cluster status
DAEMON ID      LAST HEARTBEAT
robot          2s ago
gpu-server     1s ago

Active dataflows: 1

adora cluster down

关闭集群(协调器和所有守护进程)。

adora cluster down [--coordinator-addr ADDR] [--coordinator-port PORT]

终止所有守护进程和协调器进程。

adora cluster install

在每台机器上将 adora-daemon 安装为 systemd 服务。通过 SSH 登录每台机器,写入 systemd 单元文件并启用服务。

adora cluster install <PATH>

Arguments:

Argument描述
PATH集群配置文件的路径

Behavior:

对每台机器,创建并启用名为 adora-daemon-<id> 的 systemd 服务。单元文件:

[Unit]
Description=Adora Daemon (<id>)
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=adora daemon --machine-id <id> --coordinator-addr <addr> --coordinator-port <port> --labels k1=v1,k2=v2 --quiet
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Example:

$ adora cluster install cluster.yml
Installing adora-daemon-robot on ubuntu@10.0.0.2... OK
Installing adora-daemon-gpu-server on ubuntu@10.0.0.3... OK
2/2 succeeded.

adora cluster uninstall

从每台机器卸载 adora-daemon systemd 服务。停止、禁用并移除 systemd 单元。

adora cluster uninstall <PATH>

Behavior:

对每台机器运行:

sudo systemctl stop adora-daemon-<id>
sudo systemctl disable adora-daemon-<id>
sudo rm -f /etc/systemd/system/adora-daemon-<id>.service
sudo systemctl daemon-reload

adora cluster upgrade

滚动升级:通过 SCP 将本地 adora 二进制文件传输到每台机器并重启守护进程。按顺序处理机器以保持可用性。

adora cluster upgrade <PATH>

Behavior:

对每台机器按顺序执行:

  1. 通过 SCP 将本地 adora 二进制文件传输到目标机器的 /usr/local/bin/adora
  2. 通过 sudo systemctl restart adora-daemon-<id> 重启 systemd 服务。
  3. 轮询协调器直到守护进程重新连接(30 秒超时,500 毫秒间隔)。

在每台机器升级期间,其他机器上的节点继续运行。

Example:

$ adora cluster upgrade cluster.yml
Upgrading robot (ubuntu@10.0.0.2)...
  SCP binary... OK
  Restart service... OK
  Waiting for reconnect... OK (3.2s)
Upgrading gpu-server (ubuntu@10.0.0.3)...
  SCP binary... OK
  Restart service... OK
  Waiting for reconnect... OK (2.8s)
2/2 succeeded.

adora cluster restart

按名称或 UUID 重启运行中的数据流。停止数据流并立即使用存储的描述符重新启动(不需要 YAML 路径)。

adora cluster restart <DATAFLOW>

Arguments:

Argument描述
DATAFLOW要重启的数据流的名称或 UUID

Example:

$ adora cluster restart my-app
Restarting dataflow `my-app`
dataflow restarted: a1b2c3d4-... -> e5f6a7b8-...

节点调度

当协调器收到数据流时,它根据数据流 YAML 中的 _unstable_deploy 部分决定哪个守护进程运行每个节点。解析优先级:machine > labels > unnamed

基于机器的调度

通过 cluster.yml 中的 id 将节点分配到特定机器:

nodes:
  - id: camera
    _unstable_deploy:
      machine: robot
    path: ./camera-driver
    outputs:
      - frames

协调器查找 machine-id 匹配的守护进程。如果没有匹配的守护进程连接,部署将失败并提示:no matching daemon for machine id "robot"

基于标签的调度

通过要求目标守护进程具有特定标签来分配节点:

nodes:
  - id: inference
    _unstable_deploy:
      labels:
        gpu: "true"
    path: ./ml-model
    inputs:
      frames: camera/frames
    outputs:
      - predictions

协调器查找第一个标签是所需标签超集的已连接守护进程。所有必需的键值对必须完全匹配。如果没有守护进程满足要求,部署将失败并提示:no daemon matches labels {"gpu": "true"}

未分配的节点

没有 _unstable_deploy 部分(或该部分为空)的节点被分配到第一个未命名的守护进程——即未使用 --machine-id 标志连接的守护进程。

resolve_daemon() 的内部工作原理

协调器在 coordinator/run/mod.rs 中解析节点放置:

resolve_daemon(connections, deploy) -> DaemonId
  1. If deploy.machine is Some(id):
       -> look up daemon by machine-id
  2. Else if deploy.labels is non-empty:
       -> find first daemon where all required labels match
  3. Else:
       -> pick first unnamed daemon

标签匹配函数遍历所有已连接的守护进程,检查每个必需的键值对是否存在于守护进程的标签集中(conn.labels.get(k) == Some(v))。这是一个超集检查:具有 {gpu: "true", arch: "arm64", role: "edge"} 的守护进程满足 {gpu: "true"} 的要求。


二进制分发

通过 distribute 字段控制节点二进制文件如何交付到远程守护进程。

Local(默认)

每个守护进程在自己的机器上从源码构建。这是当前的默认行为。

nodes:
  - id: my-node
    _unstable_deploy:
      machine: edge-01
      distribute: local
    path: ./my-node

SCP 模式

CLI 在生成前通过 SSH/SCP 将本地构建的二进制文件推送到目标机器。

nodes:
  - id: my-node
    _unstable_deploy:
      machine: edge-01
      distribute: scp
    path: ./my-node

HTTP 模式

协调器运行制品存储。守护进程在生成前通过 HTTP 从协调器拉取二进制文件。

nodes:
  - id: my-node
    _unstable_deploy:
      machine: edge-01
      distribute: http
    path: ./my-node

制品通过协调器 WebSocket 端口上的 GET /api/artifacts/{build_id}/{node_id} 提供。该端点需要认证(Bearer token)并对节点 ID 进行清理以防止路径遍历。

何时使用每种策略

Strategy最适用于Tradeoffs
local同构集群、CI 构建需要在每台机器上安装构建工具链
scp异构集群、交叉编译的二进制文件需要从 CLI 到所有机器的 SSH 访问
http隔离的守护进程、防火墙网络需要所有守护进程能访问协调器

systemd 服务管理

对于生产部署,将守护进程安装为 systemd 服务,使其在重启后存活并在故障时自动重启。

Install

adora cluster install cluster.yml

在每台机器上创建 systemd 单元文件(完整单元模板见 adora cluster install)。关键属性:

  • Restart=on-failure 配合 RestartSec=5:守护进程崩溃时自动重启。
  • After=network-online.target:启动前等待网络就绪。
  • WantedBy=multi-user.target:开机启动。

Uninstall

adora cluster uninstall cluster.yml

停止、禁用并从每台机器移除单元文件,然后重新加载 systemd 守护进程。

验证服务状态

安装后,直接检查服务:

ssh ubuntu@10.0.0.2 sudo systemctl status adora-daemon-robot

自动恢复

当守护进程断开并重新连接时(例如网络闪断、机器重启或服务重启后),协调器自动在该守护进程上重新生成所有缺失的数据流。

工作原理

  1. 守护进程重新连接并发送 StatusReport,列出当前运行的数据流。
  2. 协调器将报告与其预期状态(应在此守护进程上有节点的数据流)进行比较。
  3. 对于分配到此守护进程但守护进程未报告的每个运行中数据流,协调器发送 SpawnDataflowNodes 命令以重新生成缺失的节点。

30 秒退避

为防止崩溃循环(例如节点在生成时立即崩溃),恢复使用每守护进程、每数据流的退避:

  • 恢复尝试后,协调器记录时间戳。
  • 同一守护进程/数据流对的后续恢复在 30 秒过去之前被跳过。
  • 当守护进程报告数据流再次运行时,退避清除。

这意味着立即崩溃的节点只会每 30 秒重新生成一次,而不是紧密循环。

限制

  • 自动恢复仅适用于通过 adora start 启动的数据流(协调器管理的)。本地 adora run 数据流不受协调器跟踪。
  • 恢复会重新生成分配到重新连接的守护进程的所有节点,而非单个节点。对于节点崩溃时的单节点重启,请使用重启策略

滚动升级

使用逐台机器顺序升级,以零停机时间升级所有集群机器上的 adora 二进制文件。

Process

adora cluster upgrade cluster.yml

对每台机器按顺序执行:

  1. SCP 将本地 adora 二进制文件传输到目标机器的 /usr/local/bin/adora
  2. 重启 systemd 服务(systemctl restart adora-daemon-<id>)。
  3. 轮询协调器直到守护进程重新连接(30 秒超时)。

由于机器逐台升级,其他机器上的节点继续运行。守护进程重新连接后,自动恢复会重新生成在该机器上运行的所有数据流节点。

前提条件

  • 守护进程必须已安装为 systemd 服务(adora cluster install)。
  • 本地 adora 二进制文件必须与集群的协调器版本兼容。
  • 所有目标机器上具有 sudo 权限的 SSH 访问。

使用场景

1. 边缘 AI 流水线(机器人 + GPU 服务器)

摄像头节点在机器人上运行,将帧发送到 GPU 服务器进行推理,结果流回机器人上的执行器。

cluster.yml:

coordinator:
  addr: 192.168.1.1

machines:
  - id: robot
    host: 192.168.1.10
    user: ubuntu
    labels:
      role: edge
  - id: gpu-server
    host: 192.168.1.20
    user: ml
    labels:
      gpu: "true"

dataflow.yml:

nodes:
  - id: camera
    _unstable_deploy:
      machine: robot
    path: ./camera-driver
    outputs:
      - frames

  - id: inference
    _unstable_deploy:
      labels:
        gpu: "true"
    path: ./ml-model
    inputs:
      frames: camera/frames
    outputs:
      - predictions

  - id: actuator
    _unstable_deploy:
      machine: robot
    path: ./actuator-driver
    inputs:
      commands: inference/predictions

2. 多机器人车队

中央协调器管理 N 个具有异构硬件的机器人。标签调度将节点路由到正确的机器,无需硬编码机器 ID。

cluster.yml:

coordinator:
  addr: 10.0.0.1

machines:
  - id: bot-01
    host: 10.0.0.11
    user: robot
    labels:
      fleet: warehouse
      lidar: "true"

  - id: bot-02
    host: 10.0.0.12
    user: robot
    labels:
      fleet: warehouse
      camera: rgbd

  - id: bot-03
    host: 10.0.0.13
    user: robot
    labels:
      fleet: warehouse
      lidar: "true"
      camera: rgbd

dataflow.yml:

nodes:
  - id: lidar-driver
    _unstable_deploy:
      labels:
        lidar: "true"
    path: ./lidar-driver
    outputs:
      - scans

  - id: camera-driver
    _unstable_deploy:
      labels:
        camera: rgbd
    path: ./camera-driver
    outputs:
      - frames

使用此配置,lidar-driver 在 bot-01 或 bot-03 上运行,camera-driver 在 bot-02 或 bot-03 上运行。

3. 机器人 CI/CD 流水线

在 CI 中自动化集群管理:

# Setup
adora cluster install cluster.yml

# Deploy new version
adora cluster upgrade cluster.yml

# Run integration tests
adora start test-dataflow.yml --name integration-test --attach

# Monitor
adora cluster status
adora top

# Cleanup
adora stop integration-test

4. 从开发到生产

StageApproach命令
本地开发单进程,无协调器adora run dataflow.yml
Staging临时守护进程,手动设置每台机器上 adora up + adora daemon
Production托管集群,systemd 服务adora cluster install cluster.yml

运维手册

初始设置清单

  1. SSH 密钥:分发 SSH 密钥,使 CLI 机器无需密码即可连接所有集群机器(BatchMode=yes)。
  2. Adora 二进制文件:在所有机器上安装 adora 二进制文件(相同版本)。
  3. 网络:确保所有机器可访问协调器端口(默认 6013)。确保守护进程之间的 Zenoh 端口开放,以支持跨机器节点通信。
  4. cluster.yml:创建包含正确 IP、用户和标签的集群配置。

日常运维

# Start a dataflow
adora start dataflow.yml --name my-app --attach

# List running dataflows
adora list

# Monitor resource usage
adora top

# View node logs
adora logs my-app <node-id> --follow

# Stop a dataflow
adora stop my-app

# Check cluster health
adora cluster status

Upgrading

  1. 在本地构建或下载新的 adora 二进制文件。
  2. 运行 adora cluster upgrade cluster.yml
  3. 使用 adora cluster status 验证所有守护进程已重新连接。
  4. 运行中的数据流通过自动恢复机制自动重新生成。

故障排除

守护进程未连接

  • 验证协调器正在运行且可访问:curl http://<addr>:6013/api/health(或检查协调器日志)。
  • 检查守护进程日志:journalctl -u adora-daemon-<id> -f(systemd)或守护进程的 stderr 输出(临时部署)。
  • 确认 --coordinator-addr--coordinator-port 与协调器的实际绑定地址匹配。

集群命令期间的 SSH 失败

  • 确保从 CLI 机器可以成功执行 ssh -o BatchMode=yes <user>@<host> echo ok
  • 检查 StrictHostKeyChecking=accept-new 对你的环境是否可接受(首次连接自动接受主机密钥)。
  • 验证 cluster.yml 中的 user 字段与目标机器上的有效 SSH 用户匹配。

标签不匹配错误

  • 错误:no daemon matches labels {"gpu": "true"}
  • 检查守护进程是否使用了正确的 --labels 标志启动。
  • 运行 adora cluster status 查看已连接的守护进程。标签在守护进程启动时从 cluster.yml 设置,运行时无法更改。

自动恢复未触发

  • 自动恢复仅适用于协调器管理的数据流(adora start),不适用于 adora run
  • 检查协调器日志中的 auto-recovery: re-spawning 消息。
  • 如果节点立即崩溃,恢复被限制为每个守护进程每个数据流每 30 秒一次。

部署 YAML 参考

每个节点上的 _unstable_deploy 部分控制放置和分发。所有字段都是可选的。

nodes:
  - id: my-node
    _unstable_deploy:
      machine: edge-01                # 来自 cluster.yml 的目标机器 ID
      labels:                          # Label requirements (superset match)
        gpu: "true"
        arch: arm64
      distribute: local                # local | scp | http
      working_dir: /opt/my-app         # 目标机器上的工作目录
    path: ./my-node

字段

Field类型默认描述
machinestringnone目标机器 ID。优先于标签。
labelsmapempty必需的守护进程标签。所有键值对必须匹配。
distributestringlocal二进制分发策略:localscphttp
working_dirpathnone目标机器上的工作目录。

解析优先级

  1. machine —— 如果设置,节点被分配到具有该机器 ID 的守护进程。
  2. labels —— 如果设置(且未设置 machine),节点被分配到标签是所需标签超集的第一个守护进程。
  3. 回退 —— 如果两者都未设置,节点被分配到第一个未命名(无 machine-id)的守护进程。

最佳实践

  • 优先使用标签而非机器 ID 以获得灵活性。标签将数据流与特定机器解耦,使添加、移除或替换硬件更容易。
  • 生产环境使用 systemd 安装。守护进程服务在重启后存活,并通过 Restart=on-failure 在故障时自动重启。
  • 在集群中使用协调器持久化adora coordinator --store redb),使协调器在重启后存活。参见协调器状态持久化
  • 在节点上设置重启策略以实现每节点弹性。与自动恢复结合实现纵深防御。参见重启策略
  • 使用多种工具监控adora cluster status 查看守护进程健康状态,adora top 查看资源使用,adora logs 查看节点输出。
  • 先在本地测试。使用 adora run dataflow.yml 开发,然后部署到集群。相同的数据流 YAML 在两种模式下都有效——_unstable_deploy 字段在本地模式下被忽略。
  • 使用滚动升级而非停止整个集群。adora cluster upgrade 每次处理一台机器以保持可用性。
  • 将 cluster.yml 与数据流定义一起纳入版本控制