尚硅谷Netty介绍(三)

NIO与零拷贝

零拷贝基本介绍

  • 零拷贝是网络编程的关键,很多性能优化都离不开,文件传输通过零拷贝提升性能
  • 在Java程序中,常用的零拷贝有mmap(内存映射)和sendFile,那么,他们在OS里,到底是怎么样的一个的设计?我们分析mmapo和sendFIle这两个零拷贝
  • 另外我们看一下NIO中如何使用零拷贝

传统IO数据读写

Java传统IO和网络编程的一段代码

术语介绍:

DMA:direcret memory access,直接内存拷贝,不适用CPU

所谓0拷贝是没有cpu拷贝,dma拷贝是不可避免的,不可能不从硬件读到kernel buffer里面去的,是从操作系统角度看得

传统IO拷贝过程:

read方法通过DMA拷贝将数据拷贝到内核buffer,再把这个内核buffer用cpu拷贝到用户buffer,我们的数据在用户buffer内进行修改,修改完毕之后,我们在用cpu拷贝到socketbuffer,最后用DMA拷贝拷贝到协议引擎

经历了4次拷贝,3次切换,一次读写进行了多次拷贝和切换

mmap优化:

  • mmap通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间数据,这样,在进行网络传输时,就可以减少内核空间到用户空间的拷贝数
  • 过程DMA拷贝到内核buffer这步还是需要操作的,通过mmap userbuffer和kernel buffer可以共享数据,不用发生一次cpu拷贝,可以直接在内核buffer中进行修改,修改完成后,拷贝到socket buffer,然后通过DMA拷贝到协议栈
  • 3次拷贝,3次切换,少了一次拷贝

sendFile优化: 

Linux2.1版本提供网络sendFile函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到SocketBuffer,同时,由于和用户态完全无关,就减少了一次上下文切换

 

 3次拷贝,2次切换

Linux在2.4版本中,做了一些修改,避免了从内核缓冲区拷贝到Socket buffer的操作,直接拷贝到协议栈,从而再减少一次数据拷贝,这次真正的实现了零拷贝,这里其实有一次数据的拷贝kernel buffer到socket buffer,但是拷贝的数据很少,例如length、offset,消耗很低,可以忽略

 零拷贝再次理解

  • 我们说的零拷贝,是从操作系统的角度来说的,因为内核缓冲区之间,没有数据时重复的,只有kernel buffer一份数据
  • 零拷贝不仅仅带来更少的数据复制,还能带来其他的行性能优势,例如更少的上下文切换,更少的CPU缓存伪共享以及无CPU校验和计算

mmap和sendFile的区别

  • mmap适合小数据量读写,sendFile适合大文件传输
  • mmap需要4次上下文切换,3次数据拷贝;sendFile需要3次上下文切换,最少两次数据拷贝
  • sendFile可以利用DMA方式,减少CPU拷贝,mmap则不能,必须从内核拷贝到sokcet buffer

原生NIO存在的问题

  • NIO的类库和API繁杂,使用麻烦:需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等
  • 需要具备其他的额外技能:要熟悉Java多线程编程,因为NIO编程涉及到Reactor模式,你必须对多线程和网络编程非常熟悉,才能编写出高质量的NIO程序
  • 开发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常流的处理等等
  • JDK NIO的Bug:例如臭名昭著的Epoll Bug,他会导致Selector空轮询,最终导致CPU100%,知道JDK1.7版本该问题仍旧存在,没有被根本解决
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值