Netty原理
1, netty实现原理?
NIO模型(同步非阻塞),主要由eventLoopGroup、channel、channelPipeline 三大类组成.
eventLoopGroup主要有两个,一个用来接收请求的线程组,一个是用来处理IO操作的线程组;前者接收到请求后将请求注册到selector上,每个selector对应多个channel管道,另一个线程组通过轮训selector的select来处理channel上的任务,channelpipeline通过handler来监听回调返回处理结果.
多路复用: 是一种同步IO模型,实现一个线程可以监视多个文件句柄,一旦某个文件句柄就绪,就能够通知应用程序进行相应读写操作;没有文件句柄就绪时就阻塞应用,交出CPU;多路是指网络连接,复用的是一个线程.
实现多路复用的三种方式: select、poll、epoll
redis、nginx采用的就是epoll模型(IO模型)
2, netty的粘包和拆包问题
首先netty采用的是TCP协议进行数据传输的
什么是粘包?
一般情况下TCP发送的数据是一个没有界限的长串的二进制数据,在发送数据之前会先将数据存在缓存区;如果缓存区没满,就继续存数据,然后一起发送出去,这个过程就是粘包.
什么是拆包?
如果一条数据存在缓存区不足了,那就需要将数据拆分成多条数据存到缓存区发送,这个过程叫拆包.
为什么数据要先存到缓存区而不直接发送到服务端?
这个是TCP协议决定的,客户端发送数据必须要先到缓存区,然后等缓存区满了才统一发送数据.
如何解决粘包、拆包问题?
1, 发送的消息定个长度: 指定每次发送数据的字节长度大小,如果不够就用空格补齐
2, 特殊符号分割: 解析消息使用特殊符号来分割每次发送的消息,发送方的消息不能有这个特殊符号.
3, 发送长度: 将每次发送消息的长度放到消息头里面,服务端根据消息头的长度来解析消息.
netty包编码器、包解码器
3, netty零拷贝实现原理
1, 避免数据流经用户空间,即 A、B两个设备进行数据传输时,从A的内核空间读缓冲区直接到B的内核空间写缓冲区,不再经过A的用户空间缓冲区. netty实现的类是FileRegion类的transferTo()方法
2, 避免数据从JVM heap到C Heap的拷贝, 即在JVM层面,程序执行一个IO操作都需要先从JVM管理的堆内存复制到使用C malloc()或类似函数分配的Heap内存(堆外内存)才能触发系统调用,而netty省去了JVM堆内存到堆外内存的复制过程
3, 减少数据在用户空间的多次拷贝,即netty的CompositeByteBuf类实现了对多个相同byteBuffer会生成一个视图,避免数据多次复制开辟多个内存空间
参照: Netty对零拷贝(Zero Copy)三个层次的实现 - 知乎
------------------------------------------------------------------------------------------------------
零拷贝的原理
1, 零拷贝的原理
背景: 以前数据从磁盘到应用程序的大概流程如下
零拷贝出现的原因:
如果应用程序不对数据做修改,从内核缓冲区到用户缓冲区,再从用户缓冲区到内核缓冲区。两次数据拷贝都需要CPU的参与,并且涉及用户态与内核态的多次切换,加重了CPU负担。
mmap+write: 适合大文件传输,小文件传输容易产生碎片
sendfile: 相对mmap有一些优化,但内核缓冲区与socket缓冲区仍然存在一次CPU拷贝
sendfile+DMA: 去掉了CPU拷贝,但无法对数据进行修改,并且需要硬件DMA支持,有一定局限性
splice: 不需要硬件支持,通过管道建立内核缓冲与socket缓冲的连接,局限在于必须要有管道