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;
操作码
命令 | 值 | 描述 |
---|---|---|
GetServerFeature | 0 | 必需,获取 Valkey 服务器提供的功能 |
SetClientFeature | 1 | 必需,协商功能并将其设置到 Valkey 服务器 |
Keepalive | 2 | 必需,检测意外的孤立连接 |
RegisterXferMemory | 3 | 必需,将“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。
- 根据不同的硬件,过多的活动队列对可能导致性能下降。