文档:RDMA 实验性支持

Valkey 通过一个可以按需动态加载的 Valkey 模块支持远程直接内存访问 (RDMA) 连接类型。

入门

RDMA 实现了网络计算机主内存之间的直接数据交换,绕过了处理器和操作系统。

因此,与 TCP/IP 相比,RDMA 提供了更好的性能。测试结果表明,Valkey Over RDMA 的 QPS(每秒查询数)提高了约 2 倍,并且延迟更低。

请注意,Valkey Over RDMA 目前仅支持 Linux。此外,在使用 Valkey Over RDMA 之前,您必须了解如何在服务器和客户端机器上配置 RDMA。

手动运行

以 RDMA 模式运行 Valkey 服务器

./src/valkey-server --protected-mode no \
     --loadmodule src/valkey-rdma.so bind=192.168.122.100 port=6379

RDMA 的绑定地址/端口可以在运行时使用以下命令修改

192.168.122.100:6379> CONFIG SET rdma-port 6380

Valkey 可以在同一端口上同时运行 RDMA 和 TCP/IP

./src/valkey-server --protected-mode no \
     --loadmodule src/valkey-rdma.so bind=192.168.122.100 port=6379 \
     --port 6379

或者在 valkey.conf 中追加 loadmodule src/valkey-rdma.so bind=192.168.122.100 port=6379,然后

./src/valkey-server valkey.conf

要测试 RDMA 服务器是否正常工作,请勿使用 valkey-cli,因为截至 Valkey 8.1,它尚不支持 RDMA。相反,有一个 shell 脚本 ./runtest-rdma,它只是封装了一个 Python 脚本 ./tests/rdma/run.py。该 Python 脚本将在本地启动一个服务器,在本地启动一个客户端,并使用 RDMA 写入/读取操作测试约 6000 个键值对。要测试远程 RDMA 连接,请指定 ./tests/rdma/rdma-test -h $remote_rdma_ip

先决条件

请注意,网络接口(本例中的 192.168.122.100)应支持 RDMA。要测试服务器是否支持 RDMA

rdma dev show (a new version iproute2 package)

或者

ibv_devices (ibverbs-utils package of Debian/Ubuntu)

性能调优

RDMA 完成队列将使用完成向量通过硬件中断来发出完成事件信号。大量的硬件中断会影响 CPU 性能。可以使用 rdma-comp-vector 来调整性能。

请参阅 RDMA CQ 完成向量

示例 1

  • 将硬件中断向量 [0, 3] 绑定到 CPU [0, 3]。
  • 将 valkey 的 CPU 亲和性设置为 CPU [4, X]。
  • 任何 valkey 服务器都使用随机的 RDMA 完成向量 [-1]。

所有 valkey 服务器将互不影响,并与内核中断隔离。

  SYS    SYS    SYS    SYS  VALKEY VALKEY     VALKEY
   |      |      |      |      |      |          |
 CPU0   CPU1   CPU2   CPU3   CPU4   CPU5   ... CPUX
   |      |      |      |
 INTR0  INTR1  INTR2  INTR3

示例 2

  • 将硬件中断向量 [0, X] 绑定到 CPU [0, X]。
  • 将 valkey [M] 的 CPU 亲和性设置为 CPU [M]。
  • Valkey 服务器 [M] 使用 RDMA 完成向量 [M]。

单个 CPU [M] 仅在其自身上下文中处理硬件中断、RDMA 完成向量 [M] 和 valkey 服务器 [M]。这避免了跨多个 CPU 的开销和函数调用,从而使每个 valkey 服务器完全相互隔离。

VALKEY VALKEY VALKEY VALKEY VALKEY VALKEY     VALKEY
   |      |      |      |      |      |          |
 CPU0   CPU1   CPU2   CPU3   CPU4   CPU5  ...  CPUX
   |      |      |      |      |      |          |
 INTR0  INTR1  INTR2  INTR3  INTR4  INTR5      INTRX

使用 0 和正数来指定 RDMA 完成向量,或指定 -1 以允许服务器为新连接使用随机向量。默认向量是 -1。

协议

该协议定义了队列对 (QP) 类型的可靠连接 (RC),类似于 TCP、通信命令和负载交换机制。这种依赖性完全基于 RDMA(又称 Infiniband)规范,并且独立于软件(包括操作系统和用户库)和硬件(包括供应商和低级传输)。

Valkey Over RDMA 具有控制平面(控制消息)和数据平面(负载传输)。

控制消息

控制消息使用固定的 32 字节大端序消息结构

typedef struct ValkeyRdmaFeature {
    /* defined as following Opcodes */
    uint16_t opcode;
    /* select features */
    uint16_t select;
    uint8_t reserved[20];
    /* feature bits */
    uint64_t features;
} ValkeyRdmaFeature;

typedef struct ValkeyRdmaKeepalive {
    /* defined as following Opcodes */
    uint16_t opcode;
    uint8_t reserved[30];
} ValkeyRdmaKeepalive;

typedef struct ValkeyRdmaMemory {
    /* defined as following Opcodes */
    uint16_t opcode;
    uint8_t reserved[14];
    /* address of a transfer buffer which is used to receive remote streaming data,
     * aka 'RX buffer address'. The remote side should use this as 'TX buffer address' */
    uint64_t addr;
    /* length of the 'RX buffer' */
    uint32_t length;
    /* the RDMA remote key of 'RX buffer' */
    uint32_t key;
} ValkeyRdmaMemory;

typedef union ValkeyRdmaCmd {
    ValkeyRdmaFeature feature;
    ValkeyRdmaKeepalive keepalive;
    ValkeyRdmaMemory memory;
} ValkeyRdmaCmd;

操作码

命令描述
GetServerFeature0必需,获取 Valkey 服务器提供的功能
SetClientFeature1必需,协商功能并将其设置到 Valkey 服务器
Keepalive2必需,检测意外的孤立连接
RegisterXferMemory3必需,将“RX 传输缓冲区”信息告知远端,远端将其用作“TX 传输缓冲区”

一旦 Valkey Over RDMA 中引入了任何新功能和命令,客户端应通过 GetServerFeature 命令检测新功能 VALKEY_RDMA_FEATURE_FOO,然后使用 SetClientFeature 命令启用该功能 VALKEY_RDMA_FEATURE_FOO。一旦 VALKEY_RDMA_FEATURE_FOO 协商成功,可选的 ValkeyRdmaFoo 命令将在连接中得到支持。

RDMA 操作

  • 通过 RDMA 'ibv_post_send' 发送控制消息,操作码为 'IBV_WR_SEND',结构为 'ValkeyRdmaCmd'。
  • 通过 RDMA 'ibv_post_recv' 接收控制消息,接收缓冲区的大小应为 'ValkeyRdmaCmd' 的大小。
  • 通过 RDMA 'ibv_post_send' 传输流数据,操作码为 'IBV_WR_RDMA_WRITE'(可选)和 'IBV_WR_RDMA_WRITE_WITH_IMM'(必需),通过 RDMA [写入][写入][写入]...[带立即数的写入] 将数据段写入连接,总缓冲区长度由立即数数据(无符号 32 位整数)描述。例如:a,[写入 128 字节][写入 256 字节][带立即数 512 写入 128 字节] 将 512 字节写入远程端,远程端只被通知一次。b,[带立即数 128 写入 128 字节][带立即数 256 写入 256 字节][带立即数 128 写入 128 字节] 将 512 字节写入远程端,远程端被通知三次。示例 a 和 b 都写入相同的 512 字节,示例 a 性能更好,但示例 b 更易于实现。

RDMA 的最大 WQE

没有具体限制,建议 WQE 为 1024。未来可能会定义/实现 WQE 的流控制。

该协议的工作流程

                                                                    valkey-server
                                                                    listen RDMA port
   valkey-client
                -------------------RDMA connect-------------------->
                                                                    accept connection
                <--------------- Establish RDMA --------------------

                --------Get server feature [@IBV_WR_SEND] --------->

                --------Set client feature [@IBV_WR_SEND] --------->
                                                                    setup RX buffer
                <---- Register transfer memory [@IBV_WR_SEND] ------
[@ibv_post_recv]
setup TX buffer
                ----- Register transfer memory [@IBV_WR_SEND] ----->
                                                                    [@ibv_post_recv]
                                                                    setup TX buffer
                -- Valkey commands [@IBV_WR_RDMA_WRITE_WITH_IMM] -->
                <- Valkey response [@IBV_WR_RDMA_WRITE_WITH_IMM] ---
                                  .......
                -- Valkey commands [@IBV_WR_RDMA_WRITE_WITH_IMM] -->
                <- Valkey response [@IBV_WR_RDMA_WRITE_WITH_IMM] ---
                                  .......


RX is full
                ----- Register transfer memory [@IBV_WR_SEND] ----->
                                                                    [@ibv_post_recv]
                                                                    setup TX buffer
                <- Valkey response [@IBV_WR_RDMA_WRITE_WITH_IMM] ---
                                  .......

                                                                    RX is full
                <---- Register transfer memory [@IBV_WR_SEND] ------
[@ibv_post_recv]
setup TX buffer
                -- Valkey commands [@IBV_WR_RDMA_WRITE_WITH_IMM] -->
                <- Valkey response [@IBV_WR_RDMA_WRITE_WITH_IMM] ---
                                  .......

                -------------------RDMA disconnect----------------->
                <------------------RDMA disconnect------------------

Valkey Over RDMA 协议旨在高效传输流数据,并与一些学术论文中介绍的几种机制有相似之处,但也存在一些差异

Valkey 如何使用 RDMA

Valkey 支持一个连接抽象框架,该框架隐藏了监听/连接/接受/关闭/读取/写入等操作。这使得连接类型可以在启动时注册到 Valkey 核心中。此外,连接类型可以是 Valkey 内置的(例如 TCP/IP 和 Unix 域套接字)或 Valkey 模块(例如 TLS)。启用 RDMA 支持需要链接额外的库,而不是 valkey-server 对共享库的额外依赖,将 Valkey Over RDMA 构建成 Valkey 模块后,用户使用 RDMA 模块启动 valkey-server 时,valkey-server 会按需加载这些额外的共享库。

限制

  • Valkey Over RDMA 是实验性的,它可能在任何次要或主要版本中发生改变或被移除。
  • Valkey Over RDMA 不支持 TLS。但理论上通过一定的工作量是可以实现的。
  • Valkey Over RDMA 仅支持 Linux。
  • 目前与复制不兼容,复制需要 TCP/TLS。
  • 根据不同的硬件,过多的活动队列对可能导致性能下降。