设置分布式 ipython/ipyparallel MPI 集群

Setting up a distributed ipython/ipyparallel MPI cluster

我正在努力了解如何使用 ipython/ipyparallel 设置分布式 MPI 集群。我没有很强的 MPI 背景。

我已按照 ipyparallel 文档中的以下说明进行操作 (Using ipcluster in mpiexec/mpirun mode),这对于在单节点计算机上分发计算非常有效。所以创建一个 mpi 配置文件,按照上面的说明配置它,然后启动集群

$ ipython profile create --parallel --profile=mpi
$ vim ~/.ipython/profile_mpi/ipcluster_config.py

然后在主机 A 上启动一个控制器和 4 个 MPI 引擎:

$ ipcontroller --ip='*' --profile=mpi    
$ ipcluster engines --n=4 --profile=mpi

运行 以下片段:

from ipyparallel import Client
from mpi4py import MPI

c = Client(profile='mpi')
view = c[:]

print("Client MPI.COMM_WORLD.Get_size()=%s" % MPI.COMM_WORLD.Get_size())
print("Client engine ids %s" % c.ids)

def _get_rank():
    from mpi4py import MPI
    return MPI.COMM_WORLD.Get_rank()

def _get_size():
    from mpi4py import MPI
    return MPI.COMM_WORLD.Get_size()

print("Remote COMM_WORLD ranks %s" % view.apply_sync(_get_rank))
print("Remote COMM_WORLD size %s" % view.apply_sync(_get_size))

产量

Client MPI.COMM_WORLD.Get_size()=1
Client engine ids [0, 1, 2, 3]
Remote COMM_WORLD ranks [1, 0, 2, 3]
Remote COMM_WORLD size [4, 4, 4, 4]

然后在主机 B 上启动 4 个 MPI 引擎。我再次 运行 产生

的片段
Client MPI.COMM_WORLD.Get_size()=1
Client engine ids [0, 1, 2, 3, 4, 5, 6, 7]
Remote COMM_WORLD ranks [1, 0, 2, 3, 2, 3, 0, 1]
Remote COMM_WORLD size [4, 4, 4, 4, 4, 4, 4, 4]

似乎来自每个 ipcluster 命令的引擎被分组到单独的通信器或大小 4,因此重复的等级。而且客户端只有一个MPI进程。

问题:

  1. ipython/ipyparallel 似乎没有在主机之间建立 MPI 连接。 ipyparallel 应该处理 MPI 设置,还是我作为用户创建 MPI 设置,如 所建议的那样?我想我的假设是 ipyparallel 会自动处理事情,但事实并非如此。
  2. 是否有关于如何使用 ipyparallel 设置分布式 MPI 的文档?我用谷歌搜索但没有发现任何明显的东西。
  3. 根据以上所述,ipython/ipyparallel是否仅设计用于处理本地 MPI 连接,以避免控制器和引擎之间的数据传输?

编辑

  1. 第一个问题的答案似乎是所有的MPI节点都必须同时启动。这是因为:

    • Dynamic Nodes in OpenMPI提示无法添加节点post-launch.
    • MPI - Add/remove node while program is running 建议 可以通过MPI_Comm_spawn添加子节点。然而,根据 MPI_Comm_spawn

      MPI_Comm_spawn tries to start maxprocs identical copies of the MPI program specified by command, establishing communication with them and returning an intercommunicator. The spawned processes are referred to as children. The children have their own MPI_COMM_WORLD, which is separate from that of the parents.

      通过 ipyparallel 代码快速 grep 表明没有使用此功能。

  2. 第二个问题的部分答案是需要使用机器文件,以便 MPI 知道它可以在哪些远程机器上创建进程。

    这里的含义是每个遥控器上的设置都是 同质的,由 Torque/SLURM 等集群系统提供。否则,如果有人试图使用随机遥控器,将不得不做一些工作以确保 mpiexec 正在执行的环境是同质的。

  3. 第三个问题的部分答案是否定的,ipyparallel 大概可以与远程 MPI 进程一起工作,但是需要为每个 MPI 进程创建一个 ipyparall 引擎。

当您 IPython 并行启动带有 MPI 的引擎时,它最终归结为一次调用:

mpiexec [-n N] ipengine

没有配置MPI。如果您在不同的主机上启动多组引擎,则每组都将位于其自己的 MPI 域中,​​这就是您所看到的。要做的第一件事是在将 IPython parallel 引入它之前,通过一次调用 mpiexec 确保一切正常。

中所述,要使用多主机 MPI,您通常需要一个机器文件来指定在多个主机上启动多个引擎。例如:

# ~/mpi_hosts
machine1 slots=4
machine2 slots=4

您可以使用简单的测试脚本进行诊断:

# test_mpi.py
import os
import socket
from mpi4py import MPI

MPI = MPI.COMM_WORLD

print("{host}[{pid}]: {rank}/{size}".format(
    host=socket.gethostname(),
    pid=os.getpid(),
    rank=MPI.rank,
    size=MPI.size,
))

和运行它:

$ mpiexec -machinefile ~/mpi_hosts -n 8 python test_mpi.py 
machine1[32292]: 0/8
machine1[32293]: 1/8
machine1[32294]: 2/8
machine1[32295]: 3/8
machine2[32296]: 4/8
machine2[32297]: 5/8
machine2[32298]: 6/8
machine2[32299]: 7/8

一旦按预期工作,您可以添加

c.MPILauncher.mpi_args = ["-machinefile", "~/mpi_hosts"]

到你的~/.ipython/profile_default/ipcluster_config.py并用

启动你的引擎
ipcluster start -n 8