卡飞资源网

专业编程技术资源共享平台

SMC-R加速TCP实践

共享内存通信SMC(Shared Memory Communication)是一种兼容socket层、使用共享内存技术实现的高性能内核网络协议栈。SMC-R,SMC over RDMA,该协议兼容socket,能够在TCP socket之间使用RDMA进行高效通讯,使得TCP 网络应用程序透明使用 RDMA(不需要做IBVerbs改造),获得高带宽、低时延的网络通信服务。SMC 是 IBM 开源到 Linux 代码中,同时 IBM 也一同提出了 IETF RFC 7609,描述 SMC-R协议是如何实现的。

SMC-R要点,高性能和透明替换:

o 是一种协议,基于共享内存模型,Linux 下为 AF_SMC,可以直接在 socket 中制定使用,和TCP等价。

o 可以借助RDMA 加速

o 混合协议:借助TCP自动建立RDMA连接,协商不成功可以回退至TCP

o 兼容socket,可以透明替换所有的 TCP 应用,应用无需改造

缺点:

  • 基于内核实现的SMC-R会走一次内核拷贝会有性能损耗。

加速的本质

关于 RDMA 的基本原理, 互联网上已经有不少资料了. 比如 RDMA杂谈 本文不再详述.

RDMA 的加速原理并不是让报文在线缆或者交换机之间传输地更快 (毕竟都是电信号, 大家没什么不同),rdma加速的原理就是硬件卸载,将本需要软件(CPU)处理的工作下放到硬件。

简单来说, RDMA 是将原本需要消耗 CPU 处理报文的工作 Offload 到网卡,CPU 不再需要花时间在 TCP 协议栈上, 而可以用省下来的 CPU 处理更多业务逻辑, 从而减少通信时延.

但要想让 RDMA 取得相较 TCP 的显著优势, 一般来说需要满足两个条件:

  • 处理业务的 CPU 资源很宝贵

反过来说, 如果业务本身并不忙, CPU 资源本身并不稀缺, 那么 RDMA 省下的 CPU 意义并不大。

  • 通信双方之间的 RTT 并不大

如果网络传输在路径上占比很大,则 RDMA 方案中将协议栈卸载到网卡的所带来的收益将变得很小。因此, RDMA 多用于数据中心内部。

另外, RDMA 其实比 TCP 对基础网络的稳定性要求更高,对丢包更难以忍受。

旧有应用的阻碍

现实的网络应用,绝大部分直接或者间接使用 posix API 与内核交互,大部分框架已经使用了socket()、bind()、listen().

RDMA 使用的 Verbs API 不一样,它的接口更多, 语义也和 posix API 大不相同。

比如 ibv_create_qp ibv_modify_qp ibv_post_send

如果决心要使用 RDMA,新的应用还可以迁就,但现存的应用怎么办?

很容易想到通过LD_PRELOAD的方式加载使用替换 TCP的协议族,直接将应用本来想创建的 TCP socket 篡改为新的 SMC-R socket。

添加图片注释,不超过 140 字(可选)

阿里云的SMC-R落地情况

参考如下网址:

https://help.aliyun.com/zh/ecs/user-guide/in-an-enterprise-x86-erdma-instance-configuration? spm=a2c4g.11186623.0.0.62b66173b0G4eo

https://help.aliyun.com/zh/ecs/user-guide/on-the-gpu-instance-configuration-erdma? spm=a2c4g.11186623.0.0.259777187tcc6I

阿里云支持小规格虚机使用smc-r,只要是以下规格族的机器就可以, 支持以下镜像

添加图片注释,不超过 140 字(可选)

还支持在GPU实例上配置smc-r, 支持以下镜像

添加图片注释,不超过 140 字(可选)

阿里云的落地场景有数据库Redis 、大数据应用Spark 、AI训练、推理场景、HPC应用等。

添加图片注释,不超过 140 字(可选)

阿里云主要加速tcp的改动

阿里云主要有两部分改动, —部分是内核改动,其实就是使内核支持smc;—部分是使用

netACC加速,看着和smc-tools的smc_run类似,都是通过LD_PRELOAD的方式加载使用替换 TCP的协议族,可能是在这个基础上进行了—些其他功能。

SMC-R配置过程

  1. 更新内核到5.10.0及以上
  2. 配置smc-r
###关闭ipv6
sysctl net.ipv6.conf.all .disable_ipv6=1
sysctl net.ipv6.conf.default.disable_ipv6=1 4
###安装smc和smc_diag模块
modprobe smc
modprobe smc_diag 8
yum install -y smc-tools
#安装完之后可以执行—下smcr d命令看smc模块是否安装成功,使用smcr -v命令查看版本
#需要smc-tools版本为1.7以上,才可以设置ueid使能smcrv2
#如果smc-tools版本低,先升级smc-tools

3. (如果两台不同的主机通信的话)添加ueid,在两台虚机(实体机同理)上都添加ueid, 而且两台虚机中的ueid必须—样才可以。

smcr ueid add WFS  ##WFS可以随意指定,但是两台虚机中的ueid名字必须—样
###添加pnet
smc_pnet -a ABC	-I eth1	-D mlx5_1 -P 1

查看是否成功添加映射

添加图片注释,不超过 140 字(可选)

HCA即支持RDMA的网卡, driver loaded表示驱动已加载

添加图片注释,不超过 140 字(可选)

perftest测试,测试RDMA网卡

添加图片注释,不超过 140 字(可选)

添加图片注释,不超过 140 字(可选)

测试SMC-R

server.c

#include 
#include 
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

#define PORT 16000
#define BACKLOG 5
#define AF_SMC 43

int main()
{
    int iSocketFD = 0;
    int iRecvLen = 0;
    int new_fd = 0;
    char buf[4096] = {0};
    struct sockaddr_in stLocalAddr = {0};
    struct sockaddr_in stRemoteAddr = {0};
    socklen_t socklen = 0;
    int ret = 0;
    iSocketFD = socket(AF_SMC, SOCK_STREAM, 0);
    if(0 > iSocketFD)
    {
        printf("创建socket失败!\n");
        return 0;
    }
    char *host = "192.168.255.3"; //当前RDMA网卡的ip地址
    inet_pton(AF_INET, host, &stLocalAddr.sin_addr);
    stLocalAddr.sin_family = AF_INET;
    stLocalAddr.sin_port = htons(PORT);
    ret = bind(iSocketFD, (void *)&stLocalAddr,
    sizeof(stLocalAddr));
    if (ret < 0 printf ret='%d\n",' ret return 0 else printf ret='%d\n",' ret if0> listen(iSocketFD, BACKLOG))
    {
        printf("监听失败!\n");
        return 0;
    }

    printf("iSocketFD: %d\n", iSocketFD);
    new_fd = accept(iSocketFD, (void *)&stRemoteAddr, &socklen);
    if(0 > new_fd)
    {
        printf("接收失败!\n");
        return 0;
    }
    else
    {
        printf("接收成功!\n");
        memset(buf, 0x42, 1024);
        send(new_fd, buf, sizeof(buf), 0);
    }
    printf("new_fd: %d\n", new_fd);
    iRecvLen = recv(new_fd, buf, sizeof(buf), 0);
    if(0 >= iRecvLen)
    {
        printf("接收失败或者对端关闭连接!\n");
    }
    else
    {
        printf("buf: %s\n", buf);
    }
    close(new_fd);
    close(iSocketFD);
    return 0;
}

client.c

#include 
#include 
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define PORT 16000
#define ADDR "192.168.255.3" //server端设置的ip地址
#define AF_SMC 43
int main()
{
    int iSocketFD = 0;
    unsigned int iRemoteAddr = 0;
    struct sockaddr_in stRemoteAddr = {0};
    socklen_t socklen = 0;
    char buf[4096] = {0};
    iSocketFD = socket(AF_SMC, SOCK_STREAM, 0);
    if(0 > iSocketFD)
    {
        printf("创建socket失败!\n");
        return 0;
    }
    stRemoteAddr.sin_family = AF_INET;
    stRemoteAddr.sin_port = htons(PORT);
    inet_pton(AF_INET, ADDR, &iRemoteAddr);
    stRemoteAddr.sin_addr.s_addr=iRemoteAddr;
    if(0 > connect(iSocketFD, (void *)&stRemoteAddr,sizeof(stRemoteAddr)))
    {
        printf("连接失败!\n");
    }
    else
    {
        printf("连接成功!\n");
        recv(iSocketFD, buf, sizeof(buf), 0);
        printf("Received:%s\n", buf);
    }
    while(1);
    close(iSocketFD);
    return 0;
}

在两台主机上分别编译:

##在两台虚机上分别编译client和server文件
gcc -o smc_client client.c
gcc -o smc_server server.c
##启动server端
./smc_server
##启动clien端
./smc_client

在client端执行smcss命令出现以下结果,Mode为SMCR说明smc-r跑通。

添加图片注释,不超过 140 字(可选)

更简单的改造SMC-R替换

刚刚是手动将环境变为scm-r,还是有很多不方便的地方。如果安装了smc-tools,直接应用前面添加smc_run即可。

以redis为例:

###在server执行,ip地址为当前RDMA网卡的ip地址
smc_run ./redis-server --bind 192.168.255.3 --port 6379 --protected-mode no --save

###在client执行,ip地址为server中设置的地址
smc_run ./redis-benchmark -h 192.168.255.3 -p 6379 -n 1000000 -t set -c 100

执行效果如下,性能有明显提升(相较于不使用smc_run)

添加图片注释,不超过 140 字(可选)

总结

SMC-R是一种优雅的加速后端的方法,可以不改动代码加速应用。缺点是会走一次内核,性能和原生rdma应用差了一点,但是如果实现SMC-R是在纯用户态(猜测阿里的netAcc即是如此实现)则没有损耗。

引用文章:

http://switch-route.gitee.io/

Savir:0. 《RDMA杂谈》专栏索引

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言