【博学谷学习记录】超强总结,用心分享|狂野架构师Netty
Netty核心架构
核心:
可扩展的事件模型
统一的通信api,简化了通信编码
零拷贝机制与丰富的字节缓冲区
传输服务:
支持socket以及datagram(数据报)
http传输服务
In-VM Pipe (管道协议,是jvm的一种进程)
协议支持:
http 以及 websocket
SSL 安全套接字协议支持
Google Protobuf (序列化框架)
支持zlib、gzip压缩
支持大文件的传输
RTSP(实时流传输协议,是TCP/IP协议体系中的一个应用层协议)
支持二进制协议并且提供了完整的单元测试
选Netty的理由
API
Netty更友好更强大
1、JDK中NIO的一些API功能薄弱且复杂,Netty隔离了JDK中NIO的实现变化及实现细节
譬如:ByteBuffer -> ByteBuf主要负责从底层的IO中读取数据到ByteBuf,然后传递给应用程序,应用程序处理完之后封装为ByteBuf,写回给IO
并发编程
Netty自身线程安全使用JDK原生API需要对多线程要 很 熟 悉 , 因 为 N I O 涉 及 到Reactor设计模式,得对里面的原理要相当的熟悉
高可用
JDK原生方式要实现高可用,需要自己实现断路重连、半包读写、粘包处理、失败缓存处理等相关操作,而Netty则做的更多,它解决了传输的一些问题譬如粘包半包现象,它支持常用的应用层协议,完善的断路重连,idle等异常处理
Bug
JDK的NIO存在bug,如经典的epoll bug,会导致CPU 100%而Netty封装的更完善。
Netty中的Reactor实现
Netty线程模型是基于Reactor模型实现的,对Reactor三种模式都有非常好的支持,并做了一定的改进,也非
常的灵活,一般情况,在服务端会采用主从架构模型
工作流程
1.Netty 抽象出两组线程池:BossGroup 和 WorkerGroup,每个线程池中都有EventLoop 线程(可以是OIO,NIO,AIO)。BossGroup中的线程专门负责和客户端建立连接,WorkerGroup 中的线程专门负责处理连接上的读写, EventLoopGroup 相当于一个事件循环组, 这个组中含有多个事件循环
2.EventLoop 表示一个不断循环的执行事件处理的线程,每个EventLoop 都包含一个 Selector,用于监听注册在其上的 Socket 网络连接(Channel)。
3.每个 Boss EventLoop 中循环执行以下三个步骤:
3.1select:轮训注册在其上的 ServerSocketChannel 的 accept 事件(OP_ACCEPT 事件)
3.2processSelectedKeys:处理 accept 事件,与客户端建立连接,生成一个SocketChannel,并将其注册到某个 Worker EventLoop 上的 Selector 上
3.3runAllTasks:再去以此循环处理任务队列中的其他任务
4.每个 Worker EventLoop 中循环执行以下三个步骤:
4.1select:轮训注册在其上的SocketChannel 的 read/write 事件(OP_READ/OP_WRITE 事件)
4.2processSelectedKeys:在对应的SocketChannel 上处理 read/write 事件
4.3runAllTasks:再去以此循环处理任务队列中的其他任务
5.在以上两个processSelectedKeys步骤中,会使用 Pipeline(管道),Pipeline 中引用了 Channel,即通过 Pipeline 可以获取到对应的 Channel,Pipeline 中维护了很多的处理器(拦截处理器、过滤处理器、自定义处理器等)。
Netty 线程模型其他事项
1.Netty 的线程模型基于主从多Reactor模型。通常由一个线程负责处理OP_ACCEPT事件,拥有 CPU 核数的两倍的IO线程处理读写事件
2.一个通道的IO操作会绑定在一个IO线程中,而一个IO线程可以注册多个通道
3.在一个网络通信中通常会包含网络数据读写,编码、解码、业务处理。默认情况下网络数据读写,编码、解码等操作会在IO线程中运行,但也可以指定其他线程池。
4.通常业务处理会单独开启业务线程池(看业务类型),但也可以进一步细化,例如心跳包可以直接在IO线程中处理,而需要再转发给业务线程池,避免线程切换
5.在一个IO线程中所有通道的事件是串行处理的。
6.通常业务操作会专门开辟一个线程池,那业务处理完成之后,如何将响应结果通过 IO 线程写入到网卡中呢?业务线程调用 Channel对象的 write 方法并不会立即写入网络,只是将数据放入一个待写入缓存区,然后IO线程每次执行事件选择后,会从待写入缓存区中获取 写入任务,将数据真正写入到网络中