Netty架构三层设计和高性能之道

文章详细介绍了Netty的三层架构设计,包括协议层、通信调度层和业务逻辑编排层,强调了Reactor线程模型在性能优化中的作用,如非阻塞I/O、零拷贝和内存池技术。此外,文中还提到了Netty的可靠性措施,如心跳检测和内存保护机制,并讨论了其高度可定制的责任链模式。
摘要由CSDN通过智能技术生成

三层架构设计

1 :协议:很多中协议,tcp协议,udp协议,邮件的协议,http协议等
2:中间通信层 通过 Channel和buffer和pipeLine进行搭配进行实现通信
3: 通信调度层 包括 Reactor 线程 NioEventLoop 及其父类,NioSocketChannel / NioServerSocketChannel 及其父类 Buffer 组件,Unsafe 组件 等,这里主要负责监听网络读写和链接操作,负责将网络区的数据读取到缓冲区,将触发各种网络事件,建立连接,读写事件将这些事件添加到pipeline管理的事件中进行后续管理

责任链层 Pipeline :很关键,负责各种网络事件在责任链中有序的传播,负责动态的编排责任链,责任链可以选择和处理自己关心事件,可以拦截或者向后传播事件,不同Handler节点功能是不同的,开发的变价吗Handler用于消息的编解码,可以将外部协议消息变成内部的POJO对象,这样对于使用者来说,只需要关心业务处理逻辑即可,不需要感知底层协议的差异和线程模型的差异,实现了架构层面的分层隔离

业务逻辑编排层 Service ChannelHandler: 业务逻辑编排层通常有两类:一类是纯粹的业务逻辑编排,还有一类是其他的应用层协议插件,用于特定协议相关的会话和链路管理。例如,CMPP 协议,用于管理和中国移动短信系统的对接。

性能问题:
1:影响最终产品的性能因素非常多,其中软件因素如下
–架构不合理
–编码不合理导致,例如:锁木用好导致的性能瓶颈问题

netty高性能设计

1:采用非阻塞的NIO类库,给予Reactor模型实现,解决了阻塞式的io
2:TCP的接受和发送缓冲区使用直接内存来代替堆内存,内存复制,通过零拷贝(基于cpu层面来讲的零拷贝)提升了io的读取和写入的性能。
3:支持通过使用内存池的循环使用ByteBuffer,避免了频繁的创建和销毁ByteBuffer带来的性能消耗
4:可配置的IO线程数,tcp参数扥,用于不同常见的参数调优,满足不同的场景使用
5:采用环形数组缓冲区实现无锁化并发编程,代替传统的线程安全容器和锁
6:合理使用线程安全容器,原子类等,提升系统的并发处理能力
7:采用 Reactor模型对关键资源使用单线程串行化的方式,避免多线程并发带来的锁竞争和额外CPU资源消耗的问题
8:通过引用计数及时的申请释放不在被引用的对象,细粒度的内存管理降低GC频率,减少了频繁gc带来的延时和CPU的消耗

可靠性

1:链路有效性:心跳检测,心跳检测需要时机,两种进行心跳检测的测试
----读空闲超时机制:当经过 连续的周期 T 没有消息可读时,触发 超时 Handler,用户可以基于 该读空闲超时 Handler 发送心跳消息,进行链路检测,如果连续 N 个周期 仍然没有读取到心跳消息,可以主动关闭这条链路。
----写空闲超时机制:当经过 连续的周期 T 没有消息要发送时,触发 超时 Handler,用户可以基于 该写空闲超时 Handler 发送心跳消息,进行链路检测,如果连续 N 个周期 仍然没有接收到对方的心跳消息,可以主动关闭这条链路。
----Netty 提供了空闲状态检测事件通知机制,用户可以订阅:空闲超时事件、读空闲超时机制、写空闲超时事件,在接收到对应的空闲事件之后,灵活地进行定制

内存保护机制:

1:通过对象引用计数器对 Netty 的 ByteBuffer 等内置对象进行细粒度的内存申请和释放,对非法的对象引用进行检测和保护。
2:通过内存池来重用 ByteBuffer,节省内存。
3: 可设置的内存容量上限,包括 ByteBuffer、线程池线程数等。

可定制性

责任链模式:
1:ChannelPipeline 基于责任链模式开发,便于业务逻辑的拦截、定制和扩展。
2: 基于接口的开发:关键的类库都提供了接口或者抽象类,如果 Netty 自身的实现无法满足用户的需求,可以由用户自定义实现相关接口。
3:提供了大量工厂类,通过重载这些工厂类可以按需创建出用户实现的对象。
4:提供了大量的系统参数供用户按需设置,增强系统的场景定制性。

在这里插入图片描述

高性能之道

RPC性能查的原因 :
1: 传统的RPC框架或者RMI远程调用过程都是采用了同步阻塞io的形式,当客户端并发来的时候,由于阻塞io的wait导致io线程经常性的阻塞。采用BIO同步阻塞,有一个独立的acceptor负责监听客户端链接,接收到客户端链接,就为其创建一个线程进行消息的处理,处理完响应之后,线程销毁,典型的一请求 一应答,不具备弹性伸缩能力,线程个数和并发访问成正比,可能会造成句柄溢出,线程堆栈异常。
2:序列化性能差:
—java序列化值是java内部的一种编解码技术,无法跨语言使用
—相比于其他开源序列化框架,java序列化码流太大,无论是网络传输还是持久到磁盘
—序列化性能差,占用资源率高

io通信三原则

1: 传输,用什么样的通道将数据发送给对方,可以选择BIO,NIO或者AIO i/o模型决定了通信的性能
2:协议:采用什么样的通信协议,HTTP 等公有协议或者内部私有协议。协议的选择不同,性能也不同。相比于公有协议,内部私有协议的性能通常可以被设计得更优
3:线程模型:数据报如何读取?读取之后的编解码在哪个线程进行,编解码后的消息如何派发,Reactor 线程模型的不同,对性能的影响也非常大

异步非阻塞通信

在 I/O 编程 过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者 I/O 多路复用技术 进行处理。I/O 多路复用技术 通过把多个 I/O 的阻塞复用到同一个 select 的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程 / 多进程模型比,I/O 多路复用 的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降低了系统的维护工作量,节省了系统资源


JDK1.5 使用 epoll 替代了传统的 select / poll,极大地提升了 NIO 通信 的性能

Netty 的 I/O 线程 NioEventLoop 由于聚合了 多路复用器 Selector,可以同时并发处理成百上千个客户端 SocketChannel。由于读写操作都是非阻塞的,这就可以充分提升 I/O 线程 的运行效率,避免由频繁的 I/O 阻塞 导致的线程挂起。另外,由于 Netty 采用了异步通信模式,一个 I/O 线程 可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统 同步阻塞 I/O “ 一连接,一线程 ” 模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升

高效的 Reactor 线程模型(舆情)

无锁化的串行设计

Netty 的 NioEventLoop 读取到消息之后,直接调用 ChannelPipeline 的 fireChannelRead(Object msg),只要用户不主动切换线程,一直会由 NioEventLoop 调用到 用户的 Handler,期间不进行线程切换。这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看是最优的。
在这里插入图片描述

零拷贝(舆情)

内存池(netty中内存池的使用Buffer)

Socket 与 SocketChannel 有什么区别

所属包不同。Socket 在 java.net 包 中,而 SocketChannel 在 java.nio 包 中。
异步方式不同。从包的不同,我们大体可以推断出他们主要的区别:Socket 是阻塞连接,SocketChannel 可以设置为非阻塞连接。使用 ServerSocket 与 Socket 的搭配,服务端 Socket 往往要为每一个 客户端 Socket 分配一个线程,而每一个线程都有可能处于长时间的阻塞状态中。过多的线程也会影响服务器的性能。而使用 SocketChannel 与 ServerSocketChannel 的搭配可以非阻塞通信,这样使得服务器端只需要一个线程就能处理所有 客户端 Socket 的请求。
性能不同。一般来说,高并发场景下,使用 SocketChannel 与 ServerSocketChannel 的搭配会有更好的性能。
使用方式不同。Socket、ServerSocket 类 可以传入不同参数直接实例化对象并绑定 IP 和 端口。而 SocketChannel、ServerSocketChannel 类 需要借助 Selector 类。
下面是 SocketChannel 方式 需要用到的几个核心类:

ServerSocketChannel:ServerSocket 的替代类, 支持阻塞通信与非阻塞通信。

SocketChannel:Socket 的替代类, 支持阻塞通信与非阻塞通信。

Selector:为 ServerSocketChannel 监控接收客户端连接就绪事件, 为 SocketChannel 监控连接服务器读就绪和写就绪事件。

SelectionKey:代表 ServerSocketChannel 及 SocketChannel 向 Selector 注册事件的句柄。当一个 SelectionKey 对象 位于 Selector 对象 的 selected-keys 集合 中时,就表示与这个 SelectionKey 对象 相关的事件发生了。在 SelectionKey 类 中有如下几个静态常量:

SelectionKey.OP_ACCEPT,客户端连接就绪事件,等于监听 serverSocket.accept(),返回一个 socket。
SelectionKey.OP_CONNECT,准备连接服务器就绪,跟上面类似,只不过是对于 socket 的,相当于监听了 socket.connect()。
SelectionKey.OP_READ,读就绪事件, 表示输入流中已经有了可读数据, 可以执行读操作了。
SelectionKey.OP_WRITE,写就绪事件, 表示可以执行写操作了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值