0


零拷贝技术浅浅析【kafka实现百万级吞吐量基础】

家人们,这期的知识点可能会让你掉几根头发,为了尽可能让你理解,进入正题前我们先来看个栗子

给女朋友送礼物

如果,我是说如果啊,你有一个女朋友(没有的不要灰心,认真看完文章可以找博主领取)

情人节来了,你想在网上给女朋友买个礼物,但是吧,网上现成的礼物直接送过去显得没诚意,为了避免被发好人卡,你想先买回来DIY一下再送

受疫情影响,快递员不能进小区,你也不能出小区,快递员先把礼物放到小区快递点,你去快递点拿,拿回家DIY完后再放回快递点,快递员再从快递点拿到礼物送到女朋友家

简单画了个流程图
在这里插入图片描述
看看这个流程,有太多不合理的地方,人的时间和精力是宝贵的,应该用来打游戏,而不是送 / 拿快递

时间过了大概好几年,物流公司研发了送快递机器人,从此以后快递小哥不用再上门送件,于是流程变成了
在这里插入图片描述
有了快递机器人,快递员解放了,但是你还需要去快递点拿礼物,DIY完了还得送回快递点,显然也不合理,有这时间我玩把中单亚索不香吗

于是你给礼物店老板提了个需求:能不能帮我DIY,然后直接寄到我女朋友家

老板觉得有道理,推出了新服务:需要DIY的用户,只需要在订单备注即可

于是流程变成了
在这里插入图片描述
你下单的时候,备注让店家帮你DIY,完事儿直接寄到女朋友家,女朋友收到快递感动到流了两斤眼泪

至此,你的两次出门也省了

回顾一下

从送礼物整个过程来看,最开始快递员需要跑路两次,你也需要跑路两次,到现在只需要机器人跑路两次

简单来说四次跑路变成了两次跑路,而这两次还都是机器人来完成,所以整个过程的人为跑路次数由4次变成了0次,这个过程我姑且称之 为零跑路


ok该来的始终还是来了,上面这个例子只是想引起你的兴趣,想要理解零拷贝,我们现在把术语代入

  • 你家 ==> 应用程序缓存
  • 快递点 ==> 操作系统内核缓存
  • durex旗舰店 ==> 磁盘
  • 女朋友家 ==> 目标磁盘或者socket

为什么要实现零拷贝

背景:文件操作属于危险操作,操作系统不可能直接把权限交给应用程序或者用户,只有内核才有权限
应用程序操作文件如复制、传输时,需要经历一下几个步骤:
从磁盘把文件复制到系统内核
从系统内核复制到应用程序
从应用程序复制到系统内核
从系统内核复制到磁盘、socket等消费端

简单画个流程图

说明:本文重点在于帮助大家理解零拷贝,关于操作系统内核方面的知识过于偏题,所以流程图画的很简单,如 “操作系统内核缓存” 其实还可细分为 “PageCache” 和 “Socket 缓冲区”,类似这些细节就不画了,而且画复杂了看着头疼
但请放心,虽然简单,但重点都没省略,丝毫不影响理解零拷贝

在这里插入图片描述
上面1、2、3、4几个步骤都是由cpu来完成,我们知道,cpu运算效率和磁盘不是一个量级

对服务器而言,cpu资源是很稀缺的,这四个复制操作一直占用cpu,显然会拉低整个系统性能

于是计算机界大佬们想了个办法,在主板上加了一块元件,叫 DMA(全称Direct Memory Access Controller,直接内存访问控制器),它是一块物理硬件,专门用于磁盘到操作系统内核缓存之间的数据复制

于是流程变成
在这里插入图片描述
红字解释:目前的网卡几乎都支持 SG-DMA(The Scatter-Gather Direct Memory Access)技术(可以用ethtool -k eth0 | grep scatter-gather命令查看是否支持),关于这点了解即可,不需要深入研究,这已经是嵌入式开发领域的知识点了,咱没必要花太多时间在上面

如果到现在有点懵,没关系,你只需要记住,有了DMA,cpu不再亲自参与整个数据复制或传输过程,只需要给DMA发送指令,告知它应该把哪个文件复制或传输到哪里即可,等DMA完成数据操作后通知cpu


再来说说DMA吧,DMA的实现依赖于操作系统和硬件:

操作系统方面,os提供了sendfile()函数
在这里插入图片描述
它接收四个参数:target端文件描述符、source端文件描述符、偏移量、数据长度

我们没有必要研究如何调用这个函数,因为Java已经帮我们做好了封装
在这里插入图片描述
你现在不需要管这个方法在哪个类中,我后面会写代码演示

kafka为什么能做到百万级吞吐量,靠的就是零拷贝模型,如果你仔细看过kafka源码,你会发现它最终调用了transferTo()方法

硬件方面,主板上增加了DMAC元件,其实不止主板,计算机发展到今天,几乎所有牵涉到io操作的地方都集成了DMAC

至此,我们可以做个小总结:所谓的零拷贝技术,其实可以理解成软件、硬件、语言的结合,目的在于减少cpu等待时间,提升数据传输效率


Talk is cheap,Show me the code

我们以复制文件为例,测试一下零拷贝模型带来的性能提升

新建一个测试文件
在这里插入图片描述
600MB
在这里插入图片描述
先来尝试下传统io复制(代码放在最后)
在这里插入图片描述

600MB花了800ms,这已经算是io中很快的了,如果用不带buffer的普通io,时间还得加3倍左右

再来看看零拷贝的nio
在这里插入图片描述

300ms左右,相对io提升了一倍多,看着不咋地,你想想高并发场景下,动不动上万次类似操作,这节约下来的时间足以让甲方激动到拍打轮椅

代码:

publicclassZeroCopyTest{publicstaticvoidmain(String[] args)throwsIOException,InterruptedException{long start =System.currentTimeMillis();File source =newFile("D:/fileTest/copy.txt");File target =newFile("D:/fileTest/copy2.txt");ioCopy(source, target);//        ioCopyWithBuffer(source, target);//        nioCopy(source, target);System.out.println(System.currentTimeMillis()- start);Thread.sleep(200);
        target.delete();}publicstaticvoidioCopy(File source,File target)throwsIOException{try(InputStream is =newFileInputStream(source);OutputStream os =newFileOutputStream(target)){byte[] buffer =newbyte[1024];int length;while((length = is.read(buffer))>0){
                os.write(buffer,0, length);}}}publicstaticvoidioCopyWithBuffer(File source,File target)throwsIOException{try(InputStream is =newBufferedInputStream(newFileInputStream(source));OutputStream os =newBufferedOutputStream(newFileOutputStream(target))){byte[] buffer =newbyte[1024];int length;while((length = is.read(buffer))>0){
                os.write(buffer,0, length);}}}publicstaticvoidnioCopy(File source,File target)throwsIOException{try(FileChannel sourceChannel =newFileInputStream(source).getChannel();FileChannel targetChannel =newFileOutputStream(target).getChannel()){for(long count = sourceChannel.size(); count >0;){long transferred = sourceChannel.transferTo(sourceChannel.position(), count, targetChannel);
                sourceChannel.position(sourceChannel.position()+ transferred);
                count -= transferred;}}}}

两根头发又无了,嘤嘤嘤~


前面说的领女朋友,其实,是骗你们的
在这里插入图片描述


ok我话说完

标签: kafka 分布式

本文转载自: https://blog.csdn.net/qq_33709582/article/details/123043821
版权归原作者 负债程序猿 所有, 如有侵权,请联系我们删除。

“零拷贝技术浅浅析【kafka实现百万级吞吐量基础】”的评论:

还没有评论