web 3.0 基础设施、数据驱动决策、核心系统数字化转型……戳此了解qcon广州站专题方向
写点什么

系列解读smc-金马国际

  • 2022 年 4 月 07 日
  • 本文字数:6314 字

    阅读完需:约 21 分钟

引言


shared memory communication over rdma (smc-r) 是一种基于 rdma 技术、兼容 socket 接口的内核网络协议,由 ibm 提出并在 2017 年贡献至 linux 内核。smc-r 能够帮助 tcp 网络应用程序透明使用 rdma,获得高带宽、低时延的网络通信服务。阿里云云上操作系统 alibaba cloud linux 3 以及龙蜥社区开源操作系统 anolis 8 配合神龙弹性 rdma (erdma) 首次将 smc-r 带上云上场景,助力云上应用获得更好的网络性能:。


由于 rdma 技术在数据中心领域的广泛使用,龙蜥社区高性能网络 sig 认为 smc-r 将成为下一代数据中心内核协议栈的重要方向之一。


为此,我们对其进行了大量的优化,并积极将这些优化回馈到上游 linux 社区。目前,龙蜥社区高性能网络 sig 是除 ibm 以外最大的 smc-r 代码贡献团体。由于 smc-r 相关中文资料极少,我们希望通过一系列文章,让更多的国内读者了解并接触 smc-r,也欢迎有兴趣的读者加入龙蜥社区高性能网络 sig 一起沟通交流。


本篇作为系列文章的第一篇,将从宏观的角度带领读者初探 smc-r。

一、从 rdma 谈起


shared memory communication over rdma 的名称包含了 smc-r 网络协议的一大特点——基于 rdma。因此,在介绍 smc-r 前我们先来看看这个高性能网络领域中的绝对主力:remote direct memory access (rdma) 技术。

1.1 为什么需要 rdma ?


随着数据中心、分布式系统、高性能计算领域的快速发展,网络设备性能进步显著,主流物理网络带宽已达到了 25-100 gb/s,网络时延也进入了十微秒的时代。


然而,网络设备性能提升的同时一个问题也逐渐显露:网络性能与 cpu 算力逐渐失配。传统网络中,负责网络报文封装、解析和用户态/内核态间数据搬运的 cpu 在高速增长的网络带宽面前逐渐显得力不从心,面临越来越大的压力。


以 tcp/ip 网络的一次数据发送与接收过程为例。发送节点 cpu 首先将数据从用户态内存拷贝至内核态内存,在内核态协议栈中完成数据包封装;再由 dma 控制器将封装好的数据包搬运到 nic 上发送到对端。接收端 nic 获得数据包后通过 dma 控制器搬运到内核态内存中,由内核协议栈解析,层层剥离帧首或包头后再由 cpu 将有效负载 (payload) 拷贝到用户态内存中,完成一次数据传输。


(图/传统 tcp/ip 网络传输模型)


在这一过程中,cpu 需要负责:


1)用户态与内核态间的数据拷贝。

2)网络报文的封装、解析工作。


这些工作“重复低级”,占用了大量 cpu 资源 (如 100 gb/s 的网卡跑到满带宽需要打满多个 cpu 核资源),使得 cpu 在数据密集型场景下无法将算力用到更有益的地方。


所以,解决网络性能与 cpu 算力失配问题成为了高性能网络发展的关键。考虑到摩尔定律逐渐失效,cpu 性能短时间内发展缓慢,将网络数据处理工作从 cpu 卸载到硬件设备的思路就成为了主流金马国际的解决方案。这使得以往专用于特定高性能领域的 rdma 在通用场景下得到愈来愈多的应用。

1.2 rdma 的优势


rdma (remote direct memory access) 是一种远程内存直接访问技术,自提出以来经过 20 余年的发展已经成为了高性能网络的重要组成。那么 rdma 是如何完成一次数据传输的呢?


(图/用户态 rdma 网络传输模型)


rdma 网络 (用户态模式) 中,具备 rdma 能力的网卡 rnic 直接从发送端用户态内存中取得数据,在网卡中完成数据封装后传输到接收端,再由接收端 rnic 将数据解析剥离,将有效负载 (payload) 直接放入用户态内存中完成数据传输。


这一过程中 cpu 除了必要的控制面功能外,几乎不用参与数据传输。数据就像是通过 rnic 直接写入到远程节点的内存中一样。因此,与传统网络相比,rdma 将 cpu 从网络传输中解放了出来,使得网络传输就像是远程内存直接访问一样方便快捷。


(图/传统网络与 rdma 网络协议栈对比)


对比传统网络协议,rdma 网络协议具有以下三个特点:


1.旁路软件协议栈


rdma 网络依赖 rnic 在网卡内部完成数据包封装与解析,旁路了网络传输相关的软件协议栈。对于用户态应用程序,rdma 网络的数据路径旁路了整个内核;对于内核应用程序,则旁路了内核中的部分协议栈。由于旁路了软件协议栈,将数据处理工作卸载到了硬件设备,因而 rdma 能够有效降低网络时延。


2.cpu 卸载


rdma 网络中,cpu 仅负责控制面工作。数据路径上,有效负载由 rnic 的 dma 模块在应用缓冲区和网卡缓冲区中拷贝 (应用缓冲区提前注册,授权网卡访问的前提下),不再需要 cpu 参与数据搬运,因此可以降低网络传输中的 cpu 占用率。


3.内存直接访问


rdma 网络中,rnic 一旦获得远程内存的访问权限,即可直接向远程内存中写入或从远程内存中读出数据,不需要远程节点参与,非常适合大块数据传输。

二、回到 smc-r


通过上述介绍,相信读者对 rdma 主要特点以及性能优势有了初步的了解。不过,虽然 rdma 技术能够带来可喜的网络性能提升,但是想使用 rdma 透明提升现有 tcp 应用的网络性能仍有困难,这是因为 rdma 网络的使用依赖一系列新的语义接口,包括 ibverbs 接口与 rdmacm 接口 (后统称 verbs 接口)。


部分 ibverbs与rdmacm接口[1]


相较于传统 posix socket 接口,verbs 接口数量多,且更接近硬件语义。对于已有的基于 posix socket 接口实现的 tcp 网络应用,想要享受 rdma 带来的性能红利就不得不对应用程序进行大量改造,成本巨大。


因此,我们希望能够在使用 rdma 网络的同时沿用 socket 接口,使现有 socket 应用程序透明的享受 rdma 服务。针对这一需求,业界提出了以下两个方案:


其一,是基于 libvma 的用户态方案。libvma 的原理是通过 ld_preload 来将应用所有 socket 调用引入自定义实现,在自定义实现中调用 verbs 接口,完成数据收发。但是,由于实现在用户态,libvma 一方面缺少内核统一资源管理,另一方面对 socket 接口的兼容性较差。


其二,是基于 smc-r 的内核态方案。作为内核态协议栈,smc-r 对 tcp 应用的兼容性相较于用户态方案会好很多,这种 100% 兼容意味着极低的推广和复用成本。此外,实现在内核态使得 smc-r 协议栈中的 rdma 资源能够被用户态不同进程共享,提高资源利用率的同时降低频繁资源申请与释放的开销。


不过,完全兼容 socket 接口就意味着需要牺牲极致的 rdma 性能 (因为用户态 rdma 程序可以做到数据路径旁路内核与零拷贝,而 smc-r 为了兼容 socket 接口,无法实现零拷贝),但这也换来兼容与易用,以及对比 tcp 协议栈的透明性能提升。未来,我们还计划拓展接口,以牺牲小部分兼容性的代价将零拷贝特性应用于 smc-r,使它的性能得到进一步改善。

2.1 透明替换 tcp


smc-r is an open sockets over rdma protocol that provides transparent exploitation of rdma (for tcp based applications) while preserving key functions and qualities of service from the tcp/ip ecosystem that enterprise level servers/network depend on!


摘自:

https://www.openfabrics.org/images/eventpresos/workshops2014/ibug/presos/thursday/pdf/05_smc-r_update.pdf


smc-r 作为一套与 tcp/ip 协议平行,向上兼容 socket 接口,底层使用 rdma 完成共享内存通信的内核协议栈,其设计意图是为 tcp 应用提供透明的 rdma 服务,同时保留了 tcp/ip 生态系统中的关键功能。


为此,smc-r 在内核中定义了新的网络协议族 af_smc,其 proto_ops 与 tcp 行为完全一致。


/* must look like tcp */static const struct proto_ops smc_sock_ops = {  .family    = pf_smc,  .owner    = this_module,  .release  = smc_release,  .bind    = smc_bind,  .connect  = smc_connect,  .socketpair  = sock_no_socketpair,  .accept    = smc_accept,  .getname  = smc_getname,  .poll    = smc_poll,  .ioctl    = smc_ioctl,  .listen    = smc_listen,  .shutdown  = smc_shutdown,  .setsockopt  = smc_setsockopt,  .getsockopt  = smc_getsockopt,  .sendmsg  = smc_sendmsg,  .recvmsg  = smc_recvmsg,  .mmap    = sock_no_mmap,  .sendpage  = smc_sendpage,  .splice_read  = smc_splice_read,};
复制代码


由于 smc-r 协议支持与 tcp 行为一致的 socket 接口,使用 smc-r 协议非常简单。总体来说有两个方法:


(图/smc-r 的使用方法)


其一,使用 smc-r 协议族 af_smc 开发。通过创建 af_smc 类型的 socket,应用程序的流量将进入到 smc-r 协议栈;


其二,透明替换协议栈。将应用程序创建的 tcp 类型 socket 透明替换为 smc 类型 socket。透明替换可以通过以下两种方式实现:


  • 使用 ld_preload 实现协议栈透明替换。在运行 tcp 应用程序时预加载一个动态库。在动态库中实现自定义 socket() 函数,将 tcp 应用程序创建的 af_inet 类型 socket 转换为 af_smc 类型的 socket,再调用标准 socket 创建流程,从而将 tcp 应用流量引入 smc-r 协议栈。


int socket(int domain, int type, int protocol){  int rc;
if (!dl_handle) initialize();
/* check if socket is eligible for af_smc */ if ((domain == af_inet || domain == af_inet6) && // see kernel code, include/linux/net.h, sock_type_mask (type & 0xf) == sock_stream && (protocol == ipproto_ip || protocol == ipproto_tcp)) { dbg_msg(stderr, "libsmc-preload: map sock to af_smc\n"); if (domain == af_inet) protocol = smcproto_smc; else /* af_inet6 */ protocol = smcproto_smc6;
domain = af_smc; }
rc = (*orig_socket)(domain, type, protocol);
return rc;}
复制代码


开源用户态工具集 smc-tools 中的 smc_run 指令即实现上述功能[2]


  • 通过 ulp ebpf 实现协议栈透明替换。smc-r 支持 tcp ulp 是龙蜥社区高性能网络 sig 贡献到上游 linux 社区的新特性。用户可以通过 setsockopt() 指定新创建的 tcp 类型 socket 转换为 smc 类型 socket。同时,为避免应用程序改造,用户可以通过 ebpf 在合适的 hook 点 (如 bpf_cgroup_inet_sock_create、bpf_cgroup_inet4_bind、bpf_cgroup_inet6_bind 等) 注入 setsockopt(),实现透明替换。这种方式更适合在容器场景下可以依据自定义规则,批量的完成协议转换。


static int smc_ulp_init(struct sock *sk){    struct socket *tcp = sk->sk_socket;    struct net *net = sock_net(sk);    struct socket *smcsock;    int protocol, ret;        /* only tcp can be replaced */    if (tcp->type != sock_stream || sk->sk_protocol != ipproto_tcp ||        (sk->sk_family != af_inet && sk->sk_family != af_inet6))        return -esocktnosupport;    /* don't handle wq now */    if (tcp->state != ss_unconnected || !tcp->file || tcp->wq.fasync_list)        return -enotconn;        if (sk->sk_family == af_inet)        protocol = smcproto_smc;    else        protocol = smcproto_smc6;        smcsock = sock_alloc();    if (!smcsock)        return -enfile;        <...>}
复制代码


sec("cgroup/connect4")int replace_to_smc(struct bpf_sock_addr *addr){    int pid = bpf_get_current_pid_tgid() >> 32;    long ret;        /* use-defined rules/filters, such as pid, tcp src/dst address, etc...*/    if (pid != desired_pid)        return 0;        <...>            ret = bpf_setsockopt(addr, sol_tcp, tcp_ulp, "smc", sizeof("smc"));    if (ret) {        bpf_printk("replace tcp with smc error: %ld\n", ret);        return 0;    }    return 0;}
复制代码


综合上述介绍,tcp 应用程序透明使用 rdma 服务可以体现在以下两个方面:


2.2 smc-r 架构


(图/smc-r 架构)


smc-r 协议栈在系统内部处于 socket 层以下,rdma 内核 verbs 层以上。是一个具备 "hybrid" 特点的内核网络协议栈。这里的 "hybrid" 主要体现在 smc-r 协议栈中混合了 rdma 流与 tcp 流:


数据流量基于 rdma 网络传输


smc-r 使用 rdma 网络来传递用户态应用程序的数据,使应用程序透明的享受到 rdma 带来的性能红利,即上图中黄色部分所示。


发送端应用程序的数据流量通过 socket 接口从应用缓冲区来到内核内存空间;接着通过 rdma 网络直接写入远程节点的一个内核态 ringbuf (remote memory buffer, rmb) 中;最后由远程节点 smc-r 协议栈将数据从 rmb 拷贝到接收端应用缓冲区中。


(图/smc-r 共享内存通信)


显然,smc-r 名称中的共享内存通信指的就是基于远程节点 rmb 进行通信。与传统的本地共享内存通信相比,smc-r 将通信两端拓展为了两个分离的节点,利用 rdma 实现了基于“远程”共享内存的通信。


(图/主流 rdma 实现)


目前,rdma 网络的主流实现有三种:infiniband、roce 和 iwarp。其中,roce 作为在高性能与高成本中权衡的方案,在使用 rdma 的同时兼容以太网协议,既保证了不错的网络性能,同时也降低了网络组建成本,因此倍受企业青睐,linux 上游社区版本的 smc-r 也因此使用 roce v1 和 v2 作为其 rdma 实现。


而 iwarp 则是基于 tcp 实现了 rdma,突破了其余两者对无损网络的刚性需求。iwarp 具备更好的可拓展性,非常适用于云上场景。阿里云弹性 rdma (erdma) 基于 iwarp 将 rdma 技术带到云上。阿里云操作系统 alibaba cloud linux 3 与龙蜥社区开源操作系统 anolis 8 中的 smc-r 也进一步支持了 erdma (iwarp),使云上用户透明无感的使用 rdma 网络。


依赖 tcp 流建立连接


除 rdma 流外,smc-r 还会为每个 smc-r 连接配备一条 tcp 连接,两者具有相同的生命周期。tcp 流在 smc-r 协议栈中主要担负以下职责:


1)动态发现对端 smc-r 能力


在 smc-r 连接建立前,通信两端并不知道对端是否同样支持 smc-r。因此,两端会首先建立一条 tcp 连接。在 tcp 连接三次握手的过程中通过发送携带特殊的 tcp 选项的 syn 包表示支持 smc-r,同时检验对端发送的 syn 包中的 tcp 选项。


(图/表示 smc-r 能力的 tcp 选项)


2)回退


若在上述过程中,通信两端其一无法支持 smc-r 协议,或是在 smc-r 连接建立过程中无法继续,则 smc-r 协议栈将回退至 tcp 协议栈。回退过程中,smc-r 协议栈将应用程序持有的文件描述符对应的 socket 替换为 tcp 连接的 socket。应用程序的流量将通过这条 tcp 连接承载,以保证数据传输不会中断。


3)帮助建立 smc-r 连接


若通信两端均支持 smc-r 协议,则将通过 tcp 连接交换 smc-r 连接建立消息 (建连过程类似 ssl 握手)。此外,还需要使用此 tcp 连接交换两侧的 rdma 资源信息,帮助建立用于数据传输的 rdma 链路。


通过上述介绍,相信读者对 smc-r 总体架构有了初步的了解。smc-r 作为一个 "hybrid" 金马国际的解决方案,充分利用了 tcp 流的通用性和 rdma 流的高性能。后面的文章中我们将对 smc-r 中的一次完整通信过程进行分析,届时读者将进一步体会到 "hybrid" 这一特点。


本篇作为 smc-r 系列文章的首篇,希望能够起到一个引子的作用。回顾本篇,我们主要回答了这几个问题:


1、为什么要基于 rdma ?


因为 rdma 能够带来网络性能提升 (吞吐/时延/cpu 占用率)。


2、为什么 rdma 能够带来性能提升?


因为旁路了大量软件协议栈,将 cpu 从网络传输过程中解放出来,使数据传输就像直接写入远程内存一样简单。


3、为什么需要 smc-r ?


因为 rdma 应用基于 verbs 接口实现,已有的 tcp socket 应用若想使用 rdma 技术改造成本高。


4、smc-r 有什么优势?


smc-r 完全兼容 socket 接口,模拟 tcp socket 接口行为。使 tcp 用户态应用程序能够透明使用 rdma 服务,不做任何改造就可以享受 rdma 带来的性能优势。


5、smc-r 的架构特点?


smc-r 架构具有 "hybrid" 的特点,融合了 rdma 流与 tcp 流。smc-r 协议使用 rdma 网络传输应用数据,使用 tcp 流确认对端 smc-r 能力、帮助建立 rdma 链路。


参考引用说明:

[1]:

[2]:

2022 年 4 月 07 日 10:431132

评论

发布
暂无评论
发现更多内容
网站地图