通过上一篇文章 《系列解读 smc-r:透明无感提升云上 tcp 应用网络性能(一)》我们了解到,rdma 相对于 tcp 具有旁路软件协议栈、卸载网络工作到硬件的特点,能有效增加网络带宽、降低网络时延与 cpu 负载。而内核网络协议 smc-r 在利用 rdma 技术的同时、又进一步完美兼容了 socket 接口,能够透明无感的为 tcp 应用带来网络性能提升。因此,龙蜥社区高性能网络 sig 认为 smc-r 将成为下一代数据中心内核协议的重要组成,对其进行了大量优化,并积极将这些优化回馈到上游 linux 社区。
本篇文章作为 smc-r 系列的第二篇,将聚焦一次完整的 smc-r 通信流程。通过具体的建连、传输、销毁过程,使读者进一步体会到 smc-r 是一个融合了通用 tcp 与高性能 rdma 的 "hybrid" 金马国际的解决方案。
通信流程
如前篇所述,使用 smc-r 协议有两种方法。其一,是在应用程序中显式创建 af_smc 族的 socket;其二,是利用 ld_preload 或 ulp ebpf 的方式透明的将应用程序中的 af_inet 族 socket 替换为 af_smc 族 socket。
我们默认使用 smc-r 通信的节点已经加载了 smc 内核模块,并通过上述方式将应用程序运行在 smc-r 协议上。接下来,我们以 first contact (通信两端建立首个连接) 场景为例,介绍 smc-r 通信流程。
确认对端能力
使用 smc-r 通信时,我们首先需要确认对端是否同样支持 smc-r 协议。因此,smc-r 协议栈为应用程序创建 smc 类型 socket (smc socket) 的同时,还会在内核创建并维护一个与之关联的 tcp 类型 socket (clcsock),并基于 clcsock 与对端建立起 tcp 连接。
在 tcp 连接三次握手中,使用 smc-r 协议的一端发送的 syn/ack 中携带了特殊的 tcp 选项 (kind = 254,magic number = 0xe2d4),用于表明自身支持 smc-r。通过检查对端发送的 syn/ack,通信节点得知其 smc-r 能力,进而决定是否继续使用 smc-r 通信。
协议回退
若在上述 tcp 握手过程中,通信两端其一表示无法支持 smc-r,则进入协议回退 (fallback) 流程。
协议回退时,应用程序所持有的 fd 对应的 smc socket 将被替换为 clcsock。从此,应用程序将使用 tcp 协议通信,从而确保数据传输不会因为协议兼容问题而中断。
需要注意的是,协议回退仅发生在通信协商过程中,如前文提到的 tcp 握手阶段,或是下文提到的 smc-r 建连阶段。为便于跟踪诊断,smc-r 协议详细分类了潜在的回退可能,用户可以通过用户态工具 smc-tools 观测到协议回退事件及原因。
建立 smc-r 连接
若在 tcp 握手中,两端均表示支持 smc-r,则进入 smc-r 建连流程。smc-r 连接的建立依赖 tcp 连接传递控制消息,这种控制消息被称为 connection layer control (clc) 消息。
clc 消息的主要职责是同步通信两端的 rdma 资源以及共享内存等信息。使用 clc 消息建立 smc-r 连接的过程与 ssl 握手类似,主要包含 proposal、accept、decline、confirm 等语义。在建连过程中,若遇到不可恢复的异常 (如 rdma 资源失效) 导致后续 smc-r 通信无法继续,也将触发前文所述的协议回退流程。
first contact 场景下,由于通信两端首次接触,两者间尚不存在使用 rdma 通信的条件。所以,在建立首个 smc-r 连接时,还将创建 smc-r 通信所需的 rdma 资源,建立 rdma 链路,申请 rdma 内存。
创建 rdma 资源
smc-r 建连初期,两端根据应用程序传递的 ip 地址在本地寻找可用 (如相同 pnet id) 的 rdma 设备,并基于找到的设备创建必要的 rdma 资源,包括 queue pair (qp),completion queue (cq),memory region (mr),protect domain (pd) 等等。
其中,qp 与 cq 是 rdma 通信的基础,提供了一套 rdma 使用者 (如 smc 内核协议栈) 与 rdma 设备 (rnic) 之间的异步通信机制。
qp 本质是存放工作任务 (work request, wr) 的工作队列 (work queue, wq)。负责发送任务的 wq 称为 send queue (sq),负责接收任务的 wq 称为 receive queue (rq),两者总是成对出现,称为 qp。用户将希望 rnic 完成的任务打包为工作队列元素 (work queue element, wqe),post 到 qp 中。rnic 从 qp 中取出 wqe,完成 wqe 中定义的工作。
cq 本质是存放工作完成信息 (work completion, wc) 的队列。rnic 完成 wr 后,将完成信息打包为完成队列元素 (completion queue element, cqe) 放入 cq 中。用户从 cq 中 poll 出 cqe,获悉 rnic 已经完成某个 wr。
建立 rdma 链路
通信两端将已创建的 rdma 资源通过 clc 消息同步到对端,进而在两端之间建立起基于 rc (reliable connection) qp 的 rdma 链路。smc-r 中将这种点对点逻辑上的 rdma 链路称为 smc-r link。一条 smc-r link 承载着多条 smc-r 连接的数据流量。
若通信节点之间存在不止一对可用的 rnic,则会建立不止一条 link。这些 link 在逻辑上组成一个小组,称为 smc-r link group。
在 linux 实现中,每个 link group 具备 1-3 条 link,最多承载 255 条 smc-r 连接。这些连接被均衡的关联到 link group 的某一 link 上。应用程序通过 smc-r 连接发送的数据将由关联的 link (也即 rdma 链路) 传输。
同一个 link group 中,所有的 link 互相“平等”。这个“平等”体现在同一 link group 中的 link 具备访问 group 中所有 smc-r 连接收发缓冲区 (下文提到的 sndbuf 与 rmb) 的权限,具备承载任意 smc-r 连接数据流的能力。因此,当某一 link 失效时 (如 rnic down),关联此 link 的所有连接可以迁移到同 link group 的另一条 link 上。这使得 smc-r 通信稳定可靠,具备一定的容灾能力。
smc-r 中,link (group) 在 first contact 时创建,在最后一条 smc-r 连接断开一段时间 (linux 实现中为 10 mins) 后销毁,具备比连接更长的生命周期。first contact 之后创建的 smc-r 连接都将尝试复用已有的 link (group)。这样的设计充分利用了已有的 rdma 资源,避免了频繁创建与销毁带来的额外开销。
申请 rdma 内存
smc-r 协议栈为每条 smc-r 连接分配了独属的收发缓冲区:sndbuf (发送缓冲区) 与 rmb (接收缓冲区,remote memory buffer)。这是两片地址连续,长度在 16 kb ~ 512 kb 间的内核态 ring buffer。
其中,sndbuf 用于存放连接待发送的数据,被注册为 dma 内存。本地 rnic 设备可以直接访问 sndbuf,从中取走有效负载 (payload)。而 rmb 用于存放远程节点 rnic 写入的数据,即连接待接收的数据。由于需要被远程节点访问,因此 rmb 被注册为 rdma 内存。
注册 rdma 内存的过程称为 memory registration,主要完成以下操作:
生成地址翻译表
rdma 使用者 (如本地/远程 smc-r 协议栈) 通常使用虚拟地址 (va) 描述内存,而 rnic 则通过物理地址 (pa) 寻址。rnic 从 wqe 或数据包中取得数据 va 后通过查表得到 pa,进而访问正确内存空间。因此 memory registration 首要任务就是形成目标内存的地址翻译表。
pin 住内存
现代 os 会置换暂不使用的内存数据,这将导致地址翻译表中的映射关系失效。因此,memory registration 会将目标内存 pin 住,锁定 va-to-pa 映射关系。
限制内存访问权限
为避免内存非法访问,memory registration 会为目标内存生成两把内存密钥:local key (l_key) 和 remote key (r_key)。内存密钥实质是一串序列,本地或远端凭借 l_key 或 r_key 访问 rdma 内存,确保内存访问合法。
smc-r 中,远程节点访问本地 rmb 所需的 addr 与 r_key 被封装为远程访问令牌 (remote token, rtoken),通过 clc 消息传递到远端,使其具备远程访问本地 rmb 的权限。
smc-r 连接销毁后,对应的 sndbuf 与 rmb 将被回收到 link group 维护的内存池中,供后续新连接复用,以此减小 rdma 内存创建/销毁对建连性能的影响。
验证 smc-r link
由于 first contact 场景下新建立的 smc-r link 尚未经过验证,所以在正式使用 link 传输应用数据前,通信两端会基于 link 发送 link layer control (llc) 消息,用于检验 link 是否可用。
llc 消息通常为请求-回复模式,用于传输 link 层面的控制信息,如添加/删除/确认 link,确认/删除 r_key 等。
(表/典型 llc 消息含义)
llc 消息的传输基于 rdma 的 send 操作完成,与之相对的是后文提到的 rdma write 操作。
send 操作又被称为“双边操作”,这是因为 send 操作要通信两端都参与进来。一次 send 的传输过程为:
接收端 rdma 使用者 (smc-r 内核协议栈) 向本地 rq 中 post rwqe,rwqe 中记录了待接收数据的长度以及预留内存地址;
发送端 rdma 使用者 (smc-r 内核协议栈) 向本地 sq 中 post swqe,swqe 中记录了待发送数据长度和内存地址。发送端 rnic 根据 swqe 记录的信息取出相应长度的数据发送到对端;
接收端 rnic 接收到数据后,取出 rq 中的第一个 rwqe,依照其中记录的内存地址和长度存放数据。
通过在 link 上收发 confirm_link 类型的 llc 消息,通信两端确认了新创建的 link 具备 rdma 通信的能力,可以用于传输 smc-r 连接数据。
基于共享内存通信
通过上述重重步骤,first contact 场景下 smc-r 建连工作终于结束。接下来,应用程序将通过已建立好的 smc-r 连接传输数据。
应用程序下发到 smc-r 连接中的数据由关联的 link 通过 rdma write 操作写入远程节点 rmb 中。
与上文提到的 send 操作不同,rdma write 又被称为“单边操作”。这是因为数据传输只有 rdma write 发起的一方参与,而接收数据一方的 rdma 使用者完全不参与数据传输,也不知晓数据的到来。一次 rdma write 操作过程如下:
前期准备阶段,接收端 rdma 使用者 (smc-r 内核协议栈) 将接收缓冲区注册为 rdma 内存,将远程访问密钥 rkey 告知发送端,使其拥有直接访问接收端内存的权限,这个过程我们在前文介绍过。
发送端 rdma 使用者 (smc-r 内核协议栈) 向 sq 中 post swqe。与 send 不同的是,rdma write 的 swqe 中不仅包含数据在本地的内存地址和长度,还包含数据即将存放在接收端的内存地址,以及访问接收端内存所需的 r_key。发送端 rnic 根据 swqe 中记录的信息将数据传输到接收端。
接收端 rnic 核实数据包中的 r_key,将数据存放到指定内存地址中。此时的接收端 rdma 使用者并不知道数据已经被写入内存。
由于 rdma write 操作不需要接收端 rdma 使用者参与,因此非常适合大量数据的直接写入。不过,由于接收端并不知晓数据到来,发送端写入数据后需要通过 send 操作发送控制消息通知接收端。在 smc-r 中,这种控制消息称为 connection data control (cdc) 消息。cdc 消息中包含 rmb 相关控制信息用以同步数据读写。
(表/cdc 消息主要内容)
在系列文章的第一篇中我们提到,smc-r 名称中的“共享内存”指的是接收端的 rmb。结合上述的 rdma write 操作与 cdc 消息,smc-r 的共享内存通信流程可以总结为:
发送端的数据通过 socket 接口,由应用缓冲区拷贝至内核 sndbuf 中 (图中未画出 sndbuf)
协议栈通过 rdma write 单边操作将数据写入接收端 rmb 中
发送端通过 send 双边操作发送 cdc 消息告知接收端有新的数据到来
接收端从 rmb 中拷贝数据至应用缓冲区
接收端通过 send 双边操作发送 cdc 消息告知发送端 rmb 中部分数据已被使用
连接关闭与资源销毁
结束数据传输后,主动关闭方发起 smc-r 连接关闭流程。与 tcp 相似,smc-r 连接也存在半关闭/全关闭状态。断开的 smc-r 连接与 link (group) 解绑,相关的 sndbuf 与 rmb 也将被回收到内存池中,等待复用。同时,与 smc-r 连接关联的 tcp 连接也进入关闭流程,最终释放。
若 link (group) 中不再存在活跃的 smc-r 连接,则等待一段时间后 (linux 实现中为 10 mins) 进入 link (group) 销毁流程。销毁 link (group) 将释放与之相关的所有 rdma 资源,包括 qp、cq、pd、mr、以及所有的 sndbuf 与 rmb。link (group) 销毁后,再次创建 smc-r 连接则需要重新经历 first contact 流程。
总结
本篇作为 smc-r 系列文章的第二篇,以 first contact 场景为例,介绍了完整的 smc-r 通信流程。
包括:通过 tcp 握手确认对端 smc-r 能力;使用 tcp 连接传递 clc 消息,交换 rdma 资源、创建 rdma 链路、建立 smc-r 连接;通过 rdma send 操作发送 llc 消息验证 link 可用;基于 link 使用 rdma write 传输应用程序数据,并利用 cdc 消息同步 rmb 中数据变化;关闭 smc-r、tcp 连接,销毁 rdma 资源等一系列过程。
上述过程充分体现了 smc-r 的 "hybrid" 特点。smc-r 既利用了 tcp 的通用性 ,如通过 tcp 连接确认对端能力,建立 smc-r 连接与 rdma 链路;又利用了 rdma 的高性能 ,如通过 link 传输应用程序数据流量。正因为如此,smc-r 能够在兼容现有 tcp/ip 生态系统关键功能的同时为 tcp 应用提供透明无感的网络性能提升。
参考链接:
[1]
评论 1 条评论