netty:高性能NIO框架-记录

概述

netty基于NIO,NIO基于epoll系统调用(linux下)

I/O多路复用中的epoll

由于poll和select所能打开的FD数目受到限制,随意改大会影响网络处理,而epoll是跟随系统内存的,改变不了,可通过cat /proc/sys/fs/file-max查看。

epoll的改进如下

  • 支持一个进程打开的FD仅受到系统最大文件句柄数限制
  • 效率不会随着FD的增加而线性下降:因为epoll是根据fd上面的callback实现的,只有活跃的fd才会调用callback,而idle状态的不会。类似伪AIO
  • 使用mmap加速内核空间和用户空间的消息传递

java的IO发展

操作系统已经提供了五种IO的处理方式,但是JAVA是逐渐提供的

BIO

传统的BIO是服务器一个客户端建立一个线程

伪异步I/O

将每个连接作为task放入线程任务池中去执行。
BIO和伪异步IO底层都是使用阻塞的read(),write()系统调用去执行。

NIO

Buffer

NIO中的读写操作都是去读写缓冲区,Buffer的底层是数组,但是提供了其他一些方便操作数组的功能。

Channel

全双工,正好映射了操作系统的全双工通信。分为两大类,文件读写的和网络读写的。

Selector

不断的轮询注册在其上的Channel,如果Channel上发生读/写事件,这个Channel就处于就绪状态,可以通过SelectionKey来获取就绪Channel的集合。

NIO2.0

称为AIO,对应于unix中的事件驱动IO

netty基础

netty的基本数据流程图如下:
netty:高性能NIO框架-记录
所以,ChannelHandler就是相当于业务逻辑处理。

Channel

对标socket

生命周期

  • ChannelUnregistered:已创建,但还没注册到EventLoop
  • ChannelRegistered:被注册到了EventLoop
  • ChannelActive:已经连接到远程节点,可以收发数据了。
  • ChannelInactive:没有连接到远程节点

当Channel的状态改变时,会生成事件转发给handler.

ChannelHandler

生命周期

  • handlerAdded:handler添加到pipeLine时调用
  • handlerRemoved:从pipeLine移除时调用
  • exceptionCaught:当有错误时产生

EventLoop

控制流、多线程处理、并发
EventLoop、EventLoopGroup、Channel之间的关系如下图:
netty:高性能NIO框架-记录
一个eventLoop可以对应多个channel,一个eventLoop就是一个线程。
服务器端添加两个group,是用的Reactor模式的主从模式,一个group处理连接,一个group处理读写。

ChannelFuture

异步通知
为其添加Listener以接收通知。

ChannelPipeLine

包含了出站和入站的handler,入站的一端是ChannelPipeLine的头部,出站的一端是尾部。出站和入站对于客户端和服务器是相对的。
当ChannelHandler被添加到pipeLine后,他会被分配一个ChannelHandlerContext,代表了该handler和pipeLine的绑定。
ctx可以获取channel,但一般还是用于写出站数据的。
Netty,有两种发送消息的方式(就是出战么),一种是写到channel中,那么消息会从pipeLine的尾端移动;一种是写到ctx中,那么消息会从下一个Handler移动。

channel、channelPipeline、ChannelHandler、ChannelHandlerContext,eventLoop的关系

每一个channel都和唯一的pipeLine绑定,每个pipeLine中有多个handler,ctx使得handler可以和其他handler交互或者和它的pipeLine交互。
每一个handler都是通过它的eventLoop来处理传递给它的事件的。
一个handler可以存在于多个pipeLine中,一个handler只和ctx绑定。如果以map来看的话,一个handler的名称就是键名,其值就是ctx

引导

引导是将eventLoop、pipeLine、Handler组织起来的。
服务端:ServerBootstarp,可以有两个EventLoopGroup;客户端:Bootstarp,只有一个引导。
服务端两个group的情况,如下图:
netty:高性能NIO框架-记录
左边是负责创建channel并且和一个EventLoop绑定,右边是一旦连接建立了,第二个group就会给该channel创建一个EventLoop.

ByteBuf

netty:高性能NIO框架-记录
主要是根据两个索引,writerIndex和readerIndex来确定几个区域。

netty解码器

为了解决粘包、拆包的问题。
TCP没有消息边界,所以对粘包、拆包的处理只能在应用层协议上。

TCP发生粘包、拆包的原因

  • 应用程序系统调用write的发送长度大于系统发送缓冲区大小
  • 进行mss大小的TCP分段;mss就是TCP最大段大小(最大长度),mss=mtu-40(在同一个网段中才是这样子,不再同一个网段就不能确定mss值,所以才引出来第三点)
  • MTU的分段

TCP粘包、拆包解决

  • 定长消息
  • 回车换行符作为结束符
  • 特殊结束符
  • 头部定义字段标识消息的总长度

netty中为这四种提供了四个解码器。