首页 > 编程知识 正文

modbustcp和rtu区别,udp和tcp的主要区别

时间:2023-05-03 21:43:19 阅读:258765 作者:3797

目录

RDMA

RDMA和TCP编程差别

Socket API

Verbs API

百度bRPC

RDMA网卡和传统网卡对比说明


RDMA

想从根本上解决CPU参与网络传输的低效问题,就要更多地借助专用芯片的能力, RDMA高性能网络势不可挡。

RDMA(Remote Direct Memory Access),可以简单理解为网卡完全绕过CPU实现两个服务器之间的内存数据交换。其作为一种硬件实现的网络传输技术,可以大幅提升网络传输效率,帮助网络IO密集的业务(比如分布式存储、分布式数据库等)获得更低的时延以及更高的吞吐。

具体来说,RDMA技术的应用要借助支持RDMA功能的网卡以及相应的驱动程序。由下图所示,一旦应用程序分配好资源,其可以直接把要发送的数据所在的内存地址和长度信息交给网卡。网卡从内存中拉取数据,由硬件完成报文封装,然后发送给对应的接收端。接收端收到RDMA报文后,直接由硬件解封装,取出数据后,直接放在应用程序预先指定的内存位置。

由于整个IO过程无需CPU参与,无需操作系统内核参与,没有系统调用,没有中断,也无需内存拷贝,因此RDMA网络传输可以做到极高的性能。在极限benchmark测试中,RDMA的时延可以做到1us级别,而吞吐甚至可以达到200G。

RDMA和TCP编程差别

需要注意的是,RDMA的使用需要应用程序的代码配合(RDMA编程)。与传统TCP传输不同,RDMA并没有提供socket API封装,而是要通过verbs API来调用(使用libibverbs)。出于避免中间层额外开销的考虑,verbs API采用了贴近硬件实现的语义形态,导致使用方法与socket API差异巨大。

因此,对大多数开发者来说,无论是改造原有应用程序适配RDMA,还是写一个全新的RDMA原生的应用程序,都不容易。

RDMA 编程难在哪里?

如图所示,在socket API中,发送接收数据主要用到的接口如下:

Socket API

其中,write和read操作中的fd是标识一个连接的文件描述符。应用程序要发送的数据,会通过write拷贝到系统内核缓冲区中;而read实际上也是从系统内核缓冲区中将数据拷贝出来。

在绝大多数应用程序里,通常都会设置fd为非阻塞的,也就是说,如果系统内核缓冲区已满,write操作会直接返回;而如果系统内核缓冲区为空,read操作也会直接返回。

为了在第一时间获知内核缓冲区的状态变化,应用程序需要epoll机制来监听EPOLLIN和EPOLLOUT事件。如果epoll_wait函数因这些事件返回,则可以触发下一次的write和read操作。这就是socket API的基本使用方法。

作为对比,在verbs API中,发送接收数据主要用到的接口如下:

Verbs API

其中,ibv_是libibverbs库中函数和结构体的前缀。ibv_post_send近似于发送操作,ibv_post_recv近似于接收操作。发送接收操作里面的qp(queue pair)近似于socket API里面的fd,作为一个连接对应的标识。wr(work request)这个结构体里包含了要发送/接收的数据所在的内存地址(进程的虚拟地址)和长度。ibv_poll_cq则作为事件检测机制存在,类似于epoll_wait。

乍一看去,RDMA编程似乎很简单,只要把上述函数替换了就可以。但事实上,上述的对应关系都是近似、类似,而不是等价。

关键区别在于,socket API都是同步操作,而RDMA API都是异步操作(注意异步和非阻塞是两个不同的概念)

具体而言,ibv_post_send函数返回成功,仅仅意味着成功地向网卡提交了发送请求,并不保证数据真的被发送出去了。如果此时立马对发送数据所在的内存进行写操作,那么发送出去的数据就很可能是不正确的。socket API是同步操作,write函数返回成功,意味着数据已经被写入了内核缓冲区,虽然此时数据未必真的发送了,但应用程序已经可以随意处置发送数据所在的内存。

另一方面,ibv_poll_cq所获取的事件,与epoll_wait获取的事件也是不同的。前者表明,之前提交给网卡的[某一发送]或[接收请求]完成了;而后者表示,有新的报文被成功发送或是接收了。这些语义上的变化会影响到上层应用程序的内存使用模式和API调用方式。

除了同步、异步的语义区别外, RDMA编程还有一个关键要素,即所有参与发送、接收的数据,所在的内存必须经过注册

所谓内存注册,简单理解,就是把一段内存的虚拟地址和物理地址间的映射关系绑定好以后注册给网卡硬件。这么做的原因在于,发送请求和接收请求所提交的内存地址,都是虚拟地址。只有完成内存注册,网卡才能把请求中的虚拟地址翻译成物理地址,才能跳过CPU做直接内存访问。内存注册(以及解注册)是一个很慢的操作,实际应用中通常需要构建内存池,通过一次性注册、重复使用来避免频繁调用注册函数。

关于RDMA编程,还有很多细节是普通网络编程所不关心的(比如流控、TCP回退、非中断模式等等),这里就不一一展开介绍了。

总而言之,RDMA编程并不是一件容易的事情。那么,如何才能让开发者快速用上RDMA这样的高性能网络技术呢?

见招拆招,在brpc中使用RDMA

百度bRPC

上面说了很多socket API和verbs API的对比,主要还是为了衬托RDMA编程本身的复杂度。事实上,在实际生产环境中,直接调用socket API进行网络传输的业务并不多,绝大多数都通过rpc框架间接使用socket API。一个完整的rpc框架,需要提供一整套网络传输的解决方案,包括数据序列化、错误处理、多线程处理等等。

brpc是百度开源的一个基于C++的rpc框架,其相对于grpc更适用于有高性能需求的场景。在传统TCP传输以外,brpc也提供了RDMA的使用方式,以进一步突破操作系统本身的性能限制。有关具体的实现细节,感兴趣的朋友可以参见github上的源码(https://github.com/apache/incubator-brpc/tree/rdma)。

brpc client端使用RDMA

brpc server端使用RDMA

上面分别列出了brpc中client和server使用RDMA的方法,即在channel和server创建时,把use_rdma这个option设置为true即可(默认是false,也就是使用TCP)。

是的,只需这两行代码。

如果你的应用程序本身基于brpc构建,那么从TCP迁移到RDMA,几分钟就够了。当然,在上述quick start之后,如果有更高级的调优需求,brpc也提供了一些运行时的flag参数可调整,比如内存池大小、qp/cq的大小、轮询替代中断等等。

下面通过echo benchmark说明brpc使用RDMA的性能收益(可以在github代码中的rdma_performance目录下找到该benchmark)。在25G网络的测试环境中,对于2KB以下的消息,使用RDMA后,server端的最大QPS提高了50%以上,200k的QPS下平均时延下降了50%以上。

Echo benchmark下server端最大QPS(25G网络)

Echo benchmark在200k QPS下的平均时延(25G网络)

RDMA对echo benchmark的性能收益仅作为参考。实际应用程序的workload与echo相差巨大。对于某些业务,使用RDMA的收益可能会小于上述值,因为网络部分的开销仅占到其业务开销的一部分。但对于另一些业务,由于避免了内核操作对业务逻辑的干扰,使用RDMA的收益甚至会高于上述值。这里举两个应用brpc的例子:

在百度分布式块存储业务中,使用RDMA相比于使用TCP,4KB fio时延测试的平均值下降了约30%(RDMA仅优化了网络IO,存储IO则不受RDMA影响)。在百度分布式内存KV业务中,使用RDMA相比于使用TCP,200k QPS下,单次查询30key的平均时延下降了89%,而99分位时延下降了96%。

RDMA 需要基础设施支持

RDMA是一种新兴的高性能网络技术,对于通信两端均可控的数据中心内网络IO密集业务,如HPC、机器学习、存储、数据库等,意义重大。我们鼓励相关业务的开发者关注RDMA技术,尝试利用brpc构建自己的应用以平滑迁移至RDMA。

但是,需要指出的是,RDMA当前还无法像TCP那样通用,有一些基础设施层面的限制需要注意:

RDMA需要网卡硬件支持。常见的万兆网卡一般不支持这项技术。RDMA的正常使用有赖于物理网络支持。

原文:【RDMA】RDMA编程和TCP编程的区别|bRPC_bandaoyu的note-CSDN博客_rdma技术

RDMA网卡和传统网卡对比说明

普通的网卡都是基于OS的TCP/IP技术为上层提供网络服务。在Linux内核中,有一个著名的结构体sk_buff,这个结构体用来暂时存储传输的数据,它贯穿于内核网络协议栈和网卡驱动,用户的收发数据都要经过sk_buff。可以推断,这种设计至少需要一次内存copy,再加上TCP/IP等的处理,整个下来就造成了不少的overhead(引入的Latency和CPU处理时间)。

RDMA在编程模型上跟Socket有几分相似之处,比如都会使用Send和Receive交换信息。在RDMA中,还有一个Queue Pair(QP)的概念,每个QP由一个Send Queue和Receive Queue组成,Send Queue用来发送数据,Receive Queue则在另一端接收数据。在进行通信前,Server和Client端都需要建立这样的Queue Pair。RDMA支持多个QP,其数量限制由对应的网卡决定。


QP中的传输使用Work Request(WR)进行,而非数据流的形式。应用程序在Work Request中指定收发数据的地址(RDMA对数据存放的地址有要求,这些地址在使用前,必须注册到IB驱动中)。除此之外,QP的Send Queue和Receive Queue还需要配备一个Completion Queue,这个Completion Queue用来保存WR处理结果(发送或者收到),WR信息可以从Completion Queue中的Work Completion(WC)中获得。

进一步讲,WR还分为Receive WR和Send WR,Receive WR用来指定另一端发过来的数据存放位置,Send WR则是实际的数据发送请求。在主机中注册的内存类型(ib_access_flags)决定了远端client操作主机内存的方式。如果具有Remote Access权限,则可以直接在Send WR中指定待操作的地址(此为RDMA Read/Write操作),主机无需参与操作;否则Send WR对远端地址没有控制权,即发送的数据的存放地址不由Send WR决定(只能Send/Recv操作),主机需要处理请求。使用哪种操作方式可以在ib_wr_opcode中指定。

这两种方式就是经常提到的one-sided和Two-sided。one-sided(RDMA Read/Write)相比于Two-sided的好处是释放了主机端的CPU,降低了传输的Latency。从下图可以看出,one-sided方式在主机端无需生成WQE,也就不需要处理Work Completion。

NVMe over Fabrics又让RDMA技术火了一把 - rodenpark - 博客园

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。