12 个稳定版本
1.4.0 | 2024年5月19日 |
---|---|
1.3.0 | 2024年5月16日 |
1.2.1 | 2023年11月29日 |
1.1.3 | 2023年9月4日 |
1.0.0 | 2022年7月8日 |
#308 在 命令行工具
35 每月下载量
1MB
862 行
多节点 SSH 命令执行器:Pegasus
在一系列 SSH 节点上运行命令列表。带有一些可选的参数化。
演示
特性
- 无密码 SSH 是你所需要的全部。
- 简单配置用于简单场景,灵活配置用于复杂场景。
- 两种模式
- 广播 模式在每个节点上运行每个命令。
- 队列 模式在每个节点上运行每个命令一次。
- 在 Pegasus 运行时修改基于文件的队列(
queue.yaml
)。 - 参数化 主机和命令。
通过示例入门
要使用 Pegasus,
- 从 GitHub 发布版或使用
cargo install pegasus-ssh
安装 Pegasus。 - 为您的节点设置无密码 SSH。
- 填充
hosts.yaml
和queue.yaml
,然后运行 Pegasus。
Pegasus 将逐个从 queue.yaml
的顶部删除条目,并在开始执行时将其移动到 consumed.yaml
。
队列模式:完成一袋工作
使用两个节点运行四个 Python 命令。
# hosts.yaml
- node-1
- node-2
# queue.yaml
- . /opt/miniconda3/etc/profile.d/conda.sh; python train.py --bs 8
- . /opt/miniconda3/etc/profile.d/conda.sh; python train.py --bs 16
- . /opt/miniconda3/etc/profile.d/conda.sh; python train.py --bs 32
- . /opt/miniconda3/etc/profile.d/conda.sh; python train.py --bs 64
$ pegasus q # stands for Queue
广播模式:地形化节点
为多个节点运行相同的命令。
# queue.yaml
- mkdir workspace
- cd workspace && git clone https://github.com/jaywonchung/dotfiles.git
- . workspace/dotfiles/install.sh
$ pegasus b # stands for Broadcast
使用节点参数并行执行
将节点分割成并行运行命令的子节点。下面,保持 四个 SSH 连接,并 并行 运行 四个 命令。
# hosts.yaml
- hostname:
- node-1
- node-2
container:
- gpu0
- gpu1
当参数化节点时,只需确保指定 hostname
键。
您可以在命令中使用这些参数。顺便说一句,模板引擎是 Handlebars。
# queue.yaml
- docker exec {{ container }} python train.py --bs 8
- docker exec {{ container }} python train.py --bs 16
- docker exec {{ container }} python train.py --bs 32
- docker exec {{ container }} python train.py --bs 64
四个子节点和四个作业。因此,所有作业将同时开始执行。
为简洁性参数化命令
如果你可以参数化节点,为什么不参数化命令呢?
# queue.yaml
- command:
- docker exec {{ container }} python train.py --bs {{ bs }}
bs: [8, 16, 32, 64]
这会产生与上面示例中完全相同的作业。当参数化命令时,只需确保指定 command
键。
测验
队列模式下将执行多少个命令?
# hosts.yaml
- hostname:
- node-1
- node-2
laziness:
- 1
- hostname:
- node-3
laziness:
- 2
# queue.yaml
- echo hi from {{ hostname }}
- command:
- for i in $(seq {{ low }} {{ high }}); do echo $i; sleep {{ laziness }}; done
- echo bye from {{ hostname }}
low:
- 1
- 2
high:
- 3
- 4
请注意,尽管 echo bye from {{ hostname }}
并未真正使用 low
或 high
参数,但它仍然会运行 2 * 2 = 4
次。
答案是 1 + 2 * 2 * 2
。
锁模式:修改队列
queue.yaml
实际上是队列。
Pegasus 在有可用主机时将移除 queue.yaml
的第一条条目。如果你在 Pegasus 拖取之前删除条目,它们将不会执行。如果你向 queue.yaml
添加条目,它们将执行。
问题:我为什么需要这个功能?
想想当剩余命令的数量小于空闲节点数量时的情况。如果没有向 Pegasus 提交更多作业的方法,那些空闲节点将保持空闲,直到所有命令执行完毕,你再次启动一个全新的 Pegasus 实例。
通过提供在命令仍在运行时向队列添加的方法,用户可以实现更高的节点利用率。能够从队列中删除只是一个副产品;向队列添加是关键功能。
问题:但这在 queue.yaml
上是一个竞态条件。
锁模式将锁定 queue.yaml
并为你启动一个命令行编辑器。
$ pegasus l --editor nvim # l stands for Lock
编辑器的优先级是 --editor
> $EDITOR
> vim
。当你保存并退出时,队列锁将被释放,Pegasus 可以访问 queue.yaml
。
问题:如果我添加到 queue.yaml
之前 Pegasus 终止了怎么办?
启用守护进程模式,即使 queue.yaml
为空,Pegasus 也不会终止。它将等待你再次填充 queue.yaml
并执行它们。
$ pegasus q --daemon
使用 Handlebars 的高级模板化
Handlebars 是一个模板引擎,Pegasus 使用 Handlebars 将参数填充到 hostname
和 command
中。
看看这个例子,看看这有多有用
# queue.yaml
- command:
- python main.py --model-path {{ model }} --output-path {{ replace model "/" "--" }}.json
- model:
- facebook/opt-13b
- facebook/opt-30b
- facebook/opt-66b
上面的命令展开为
# queue.yaml
- python main.py --model-path facebook/opt-13b --output-path facebook--opt-13b.json
- python main.py --model-path facebook/opt-30b --output-path facebook--opt-30b.json
- python main.py --model-path facebook/opt-66b --output-path facebook--opt-66b.json
在这里,facebook/opt-13b
是一个模型块的名字(并且你需要包含 /
以便 Hugging Face 能够理解),但是如果你只是让脚本以 facebook/opt-13b.json
的格式输出结果,它将创建一个名为 facebook
的目录,并将 opt-13b.json
保存在其中。这不是一个好的做法。相反,我们只是使用了来自 handlebars_misc_helpers
的 字符串转换 部分的 replace
助手,基本上执行了 model.replace("/", "--")
。
详细信息
Pegasus 使用 sh -c
来运行命令
你放入 queue.yaml
中的命令会被 sh -c
单独包装,并通过 SSH 执行。在你的主机上,sh
可能链接到 bash
、dash
或其他,并且某些语法可能允许或不允许(例如,双重括号)。
队列.yaml
这是队列文件。从 queue.yaml
中读取条目,逐个读取。此外,只有在有新主机可供执行新命令时,条目才会被读取。读取的条目会立即附加到 consumed.yaml
中,以“规范形式”呈现,其中每个条目都有一个 command
键。因此,你可以执行类似 tail -n 2 consumed.yaml > queue.yaml
的操作来重新执行之前的单行命令。
如前所述,当需要修改 queue.yaml
时,始终使用锁模式。
广播模式
在广播模式下,主机之间保持同步。也就是说,当所有主机完成执行上一个命令后,将从 queue.yaml
中获取下一个命令并在所有主机上执行。
考虑以下情况
fast-host slow-host
- command1 success success
- command2 success fail!
- command3 success
- command4 running
在这种情况下,我们希望为 command2
预先添加一个撤销命令(例如,rm -rf repo || true
)并从那里重新开始,但是 fast-host
已经远远领先,这使得事情变得复杂。因此,特别是在使用 Pegasus 修改节点时,保持主机同步应该是有益的。
广播模式还有一个 -e
或 --error-aborts
标志,当主机在命令中失败时,会自动中止 Pegasus。
取消和终止
很难找到一种通用的方法来取消通过 SSH 启动的命令(见 #11)。因此,Pegasus 目前的限制是,当事情顺利时,它工作得很好,但当事情不顺利时,取消和终止变得困难。你需要进入每个节点并手动终止命令。话虽如此,你仍然可以使用广播模式来自动化这个过程。
依赖项
~11–26MB
~348K SLoC