启用 UCX 通信

使用 UCX 通信的 CUDA 集群可以通过 LocalCUDACluster 自动启动,或通过 dask cuda worker CLI 工具手动启动。无论哪种情况,都必须为工作进程集群创建使用相同 Dask UCX 配置的 dask.distributed.Client;有关所有可用选项的详细信息,请参阅UCX 集成 – 配置

使用自动配置的 LocalCUDACluster

自动配置在 Dask-CUDA 22.02 中引入,需要 UCX >= 1.11.1。这允许用户仅指定 UCX 协议,让 UCX 决定使用哪些传输方式。

要将客户端连接到使用自动配置的 UCX 和 RMM 池的集群

from dask.distributed import Client
from dask_cuda import LocalCUDACluster

cluster = LocalCUDACluster(
    protocol="ucx",
    interface="ib0",
    rmm_pool_size="1GB"
)
client = Client(cluster)

注意

上面特意指定 interface="ib0" 以确保在支持 InfiniBand 的系统中使用了 RDMACM。在不支持 InfiniBand 或不需要 RDMACM 的系统上,可以省略 interface 参数,或指定监听其他接口。

使用手动配置的 LocalCUDACluster

当使用手动配置的 LocalCUDACluster 和 UCX 通信时,所有必需的 UCX 配置都通过构造函数提供的参数处理;有关这些参数的完整列表,请参阅API – Cluster。要将客户端连接到支持所有传输方式和 RMM 池的集群

from dask.distributed import Client
from dask_cuda import LocalCUDACluster

cluster = LocalCUDACluster(
    protocol="ucx",
    interface="ib0",
    enable_tcp_over_ucx=True,
    enable_nvlink=True,
    enable_infiniband=True,
    enable_rdmacm=True,
    rmm_pool_size="1GB"
)
client = Client(cluster)

使用自动配置的 dask cuda worker

当使用自动配置的 dask cuda worker 和 UCX 通信时,调度器、工作进程和客户端都必须手动启动,但无需显式指定任何 UCX 传输方式。这仅在 Dask-CUDA 22.02 及更新版本中支持,并且需要 UCX >= 1.11.1。

调度器

对于自动 UCX 配置,我们必须确保在 UCX 初始化之前,调度器上已创建 CUDA 上下文。这可以通过在创建调度器时指定环境变量 DASK_DISTRIBUTED__COMM__UCX__CREATE_CUDA_CONTEXT=True 来实现。

要启动使用 UCX 进行自动配置和 1GB RMM 池的 Dask 调度器

$ DASK_DISTRIBUTED__COMM__UCX__CREATE_CUDA_CONTEXT=True \
> DASK_DISTRIBUTED__RMM__POOL_SIZE=1GB \
> dask scheduler --protocol ucx --interface ib0

注意

上面特意指定 interface="ib0" 以确保在支持 InfiniBand 的系统中使用了 RDMACM。在不支持 InfiniBand 或不需要 RDMACM 的系统上,可以省略 interface 参数,或指定监听其他接口。

上面我们指定了 UCX_MEMTYPE_REG_WHOLE_ALLOC_TYPES=cuda 以在 InfiniBand 环境中获得最佳性能,详细信息请参阅此处。如果不使用 InfiniBand,可以省略该选项。在 UCX 1.12 及更高版本中,该选项是默认的,即使在使用 InfiniBand 时也可以省略。

工作进程

要启动使用 UCX 进行自动配置和每个 GPU 14GB RMM 池的工作进程

$ UCX_MEMTYPE_REG_WHOLE_ALLOC_TYPES=cuda
> dask cuda worker ucx://<scheduler_address>:8786 \
> --rmm-pool-size="14GB" \
> --interface="ib0"

注意

类似于调度器的设置,上面特意指定了 interface="ib0" 以确保在支持 InfiniBand 的系统中使用了 RDMACM。在不支持 InfiniBand 或不需要 RDMACM 的系统上,可以省略 interface 参数,或指定监听其他接口。

上面我们指定了 UCX_MEMTYPE_REG_WHOLE_ALLOC_TYPES=cuda 以在 InfiniBand 环境中获得最佳性能,详细信息请参阅此处。如果不使用 InfiniBand,可以省略该选项。在 UCX 1.12 及更高版本中,该选项是默认的,即使在使用 InfiniBand 时也可以省略。

客户端

要将客户端连接到我们启动的使用 UCX 进行自动配置的集群

import os

os.environ["UCX_MEMTYPE_REG_WHOLE_ALLOC_TYPES"] = "cuda"

import dask
from dask.distributed import Client

with dask.config.set({"distributed.comm.ucx.create_cuda_context": True}):
    client = Client("ucx://<scheduler_address>:8786")

或者,可以省略上面示例中的 with dask.config.set 语句,而改用环境变量 DASK_DISTRIBUTED__COMM__UCX__CREATE_CUDA_CONTEXT=True

import os

os.environ["UCX_MEMTYPE_REG_WHOLE_ALLOC_TYPES"] = "cuda"
os.environ["DASK_DISTRIBUTED__COMM__UCX__CREATE_CUDA_CONTEXT"] = "True"

from dask.distributed import Client

client = Client("ucx://<scheduler_address>:8786")

注意

上面我们指定了 UCX_MEMTYPE_REG_WHOLE_ALLOC_TYPES=cuda 以在 InfiniBand 环境中获得最佳性能,详细信息请参阅此处。如果不使用 InfiniBand,可以省略该选项。在 UCX 1.12 及更高版本中,该选项是默认的,即使在使用 InfiniBand 时也可以省略。

使用手动配置的 dask cuda worker

当使用手动配置的 dask cuda worker 和 UCX 通信时,调度器、工作进程和客户端都必须手动启动,并且每个都使用相同的 UCX 配置。

调度器

UCX 配置选项需要作为环境变量为 dask scheduler 指定;有关环境变量和选项之间映射的更多详细信息,请参阅Dask 配置 – 环境变量

要启动使用 UCX 并支持所有传输方式和千兆字节 RMM 池的 Dask 调度器

$ DASK_DISTRIBUTED__COMM__UCX__CUDA_COPY=True \
> DASK_DISTRIBUTED__COMM__UCX__TCP=True \
> DASK_DISTRIBUTED__COMM__UCX__NVLINK=True \
> DASK_DISTRIBUTED__COMM__UCX__INFINIBAND=True \
> DASK_DISTRIBUTED__COMM__UCX__RDMACM=True \
> DASK_DISTRIBUTED__RMM__POOL_SIZE=1GB \
> dask scheduler --protocol ucx --interface ib0

我们通过 --protocol 选项通知调度器我们将使用 UCX,并通过 --interface 选项通知它我们将使用 InfiniBand。

工作进程

所有 UCX 配置选项在 dask cuda worker 中都有类似的选项;有关这些选项的完整列表,请参阅API – Worker。要启动支持所有传输方式和 RMM 池的集群

$ dask cuda worker ucx://<scheduler_address>:8786 \
> --enable-tcp-over-ucx \
> --enable-nvlink \
> --enable-infiniband \
> --enable-rdmacm \
> --rmm-pool-size="1GB"

客户端

可以通过使用 dask_cuda.initialize 来配置客户端使用 UCX,这是一个实用程序,它接受与 LocalCUDACluster 相同的 UCX 配置参数,并将其添加到创建客户端时使用的当前 Dask 配置中;有关参数的完整列表,请参阅API – Client initialization。要连接客户端到我们创建的集群

from dask.distributed import Client
from dask_cuda.initialize import initialize

initialize(
    enable_tcp_over_ucx=True,
    enable_nvlink=True,
    enable_infiniband=True,
    enable_rdmacm=True,
)
client = Client("ucx://<scheduler_address>:8786")