导语 | 本文介绍了局部高性能网络计划,包含RDMA、HARP、io_uring等。从技术原理、落地可行性等方面,简要地做出剖析,心愿能对此方面感兴趣的开发者提供一些教训和帮忙。
一、背景
业务中常常会有这样的场景:
随着网卡速率的晋升(10G/25G/100G),以及局部业务对低提早的极致谋求(1ms/50us),目前的内核协定栈因为协定简单、流程简单、设计古老等因素,曾经逐步成为业务瓶颈。
业界曾经有局部RDMA、DPDK的实际,然而对于大多数开发者而言,仍然比拟生疏。
那么这些计划各自的场景到底怎么?是否可能为更多的业务赋能?以下是阶段性简要总结。
二、RDMA
(一)原理简介
绝对于传统的网络协议栈,RDMA提供的要害个性即为:Kernel Bypass,也即利用专用的NIC(网卡)进行硬件层面的协定传输、编解码(Offload),通过内存映射技术间接与用户态程序交互,从而防止了简单低效的内核中介。
基于这种设计,随之提供几个额定的重要个性:
- Zero-Copy:基于DMA操作,通信全程没有额定的CPU染指拷贝,从而升高CPU耗费。
- 稳固低提早:因为硬件通路的可靠性,从而保障了稳固的通信提早。
- 多种传输模式:RC、RD、UC、UD等。基于不同业务的不同可靠性和性能需求,提供相似TCP/UDP的多种传输模式。
因为RDMA定位为高性能网络传输,同时也为了简化硬件的设计,一般来说,RDMA会防止如软件TCP那样简单的可靠性设计,而是极其依赖底层传输网络的可靠性。
依据不同的传输网络,RDMA的具体实现分为几类:
另外补充阐明:
- 尽管RoCE v1/2依赖交融交融以太网,也即无损传输,不过也有局部厂商的优化实现,能够加重对无损传输的依赖。
- Linux kernel 4.9+中,实现了Soft-RoCE,也即软件版本的RoCE v2,次要用于测试、学习。
(二)RoCE v2 v.s. iWARP
在以太网环境,次要可选项为RoCE v2和iWARP,相干比照如下:
目前来看,目前的机房网络建设中,对RoCE v2的反对更好,而iWARP却依然处于绝对空白的状态。
为此,以后的调研次要针对RoCE v2,而iWARP依然有待摸索。
(三)业务落地
后盾业务支流协定依然是TCP,具备运行稳固、调试工具丰盛等劣势。不过对于多数冀望高性能的业务,RDMA也是值得思考的。
业务应用RDMA次要面临两方面的艰难:
- RoCE v2无损网络的要求导致难以跨机房传输,以后腾讯机房的反对为module内传输(如5跳之内)。
- 全新的开发接口如libverbs、UCX等,业务软件须要进行适配。
而有些存储业务依赖多正本,网络传输须要可能逾越MAN,甚至跨城市传输。这间接导致RoCE v2难以落地。
三、io_uring/socket
(一)原理简介
io_uring是Linux 5.1+中反对的异步IO框架,其外围劣势有:
- 真正的异步化设计(Proactor),而非如epoll等实质上的同步行为(Reactor)。而其关键在于,程序和kernel通过SQ/CQ两个队列进行解耦。
- 对立的异步IO框架,不仅反对存储、网络。因为良好的扩展性,甚至能够反对任何的零碎调用,如openat、stat等。
如前述,一个io_uring的实例,会建设一对内核和用户程序共享的队列,也即提交队列SQ和实现队列CQ,两者皆为SPSC范型: - SQ:用户态线程生产,而后零碎调用(io_uring_enter)告诉内核(io_wq kernel thread)生产。其中元素称为SQE。
- CQ:内核生产,而后告诉(若用户程序睡眠期待则唤醒)用户态生产。其中元素称为CQE。
这其实是最惯例也是最经典的异步模型,在泛滥异步设计中可见。
个别状况下,CQE和SQE一一对应,不过io_uring反对multi-shot模式后则不肯定如此。
另外,io_uring反对批量生产和生产,也即间断生产多个SQ后,一次性告诉内核,或者继续生产CQ直到其空。
为了进一步优化局部场景的性能,io_uring反对泛滥的高级个性:
- File Registration:在重复操作同一个fd时,减速其查找映射。
- Buffer Registration:在read/write等重复须要在内核和用户程序替换数据的场景,能够反复利用预注册的一批内存。
- Automatic Buffer Selection:为Proactor read预注册一批内存,在就绪后内核主动抉择其中一块存放数据,从而缩小内存调配开释,也节约内存资源。
- SQ Polling:使内核(io_wq)轮询SQ指定工夫才睡眠,从而缩小告诉的零碎调用。
- IO Polling:开启子系统(存储、网络等)的轮询模式(须要设施驱动反对),从而减速局部高速设施。另外能够配合io_uring_enter(flag:IORING_ENTER_GETEVENTS)进行忙等。
- Multi-Shot:一次提交,屡次实现,如只有一次提交socket accept,后续连贯到来后屡次返回。
- io_uring在存储IO场景,绝对之前的阻塞IO、glibc aio、linux aio等,都有不错的性能晋升。
那么在网络IO场景呢?是否优于epoll等计划呢?
(二)测试数据
通过调研,在出名开源软件中,暂未发现间接采纳io_uring进行网络IO的计划,如seastar/nginx等都没有官网反对,既然可借鉴较少,那么就自行测试。
因为io_uring还处于欠缺阶段,而且对于网络IO的反对也有多种形式。目前咱们梳理出其中3种:
- Proactor:io_uring间接recv/send。
- Reactor:io_uring接管socket_fd(POLL_ADD)后再recv/send。
- io_uring接管epoll_fd后再epoll_wait再RECV/SEND:门路繁琐,揣测性能不佳,间接略过。
为此,咱们针对前两种io_uring模型,以及罕用的epoll模型,进行测试比照。
为了利用更多的io_uring个性,测试采纳以后最新kernel(5.15)。测试模型如下:
- 通信协议:tcp echo
- 服务模型:单线程,异步并发
- 压测客户端:多线程,每个线程一个连贯同步测试
- 数据:包大小为512B
- 测试环境:本机通信loopback接口
epoll
- io_uring(Proactor)
- io_uring(Reactor)
目前网上的很多程序采纳此形式。不过从实践上剖析,应该epoll性能靠近,故暂未测试。
(三)数据分析
通过比照、剖析以上的测试数据,能够失去以下论断:
- io_uring在网络IO方面,并不比epoll性能弱小。网络IO的次要瓶颈还是在于内核协定栈的开销。
io_uring即便开启内核轮询,在负载低时可升高延时,而满载性能晋升不显著,反而节约了CPU资源。
(四)业务落地
在Linux网络IO场景中,io_uring并不比epoll带来额定的性能晋升。这与存储IO不同。
不过值得思考的是,如果一个零碎中同时存在网络IO和存储IO,比照以下两种形式:
- 网络IO采纳epoll,存储IO采纳io_uring(可联合eventfd与epoll配合)
- 网络IO、存储IO都采纳io_uring。
从实践上剖析,形式2能够依赖io_uring批量提交等优化,从而进一步缩小零碎调用,是否能够带来性能晋升呢?
这部分须要进一步测试剖析。
四、总结
以上简略介绍了RDMA、io_uring/socket等计划,各有优缺点以及场景限度。后续将介绍DPDK的计划,敬请期待。
作者简介
quintonwang,腾讯后盾开发工程师。