Netty技术点整理

Netty是什么?

1)本质:基于NIO的通信框架做的一个 Jar 包
2)目的:快速开发高性能、高可靠性的网络服务器和客户端程序
3)优点:提供异步的、事件驱动的网络应用程序框架和工具。

Netty为什么并发高

Netty 是一款基于 NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比于BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高

Netty为什么传输快

Netty 的传输快其实也是依赖了 NIO 的一个特性——零拷贝。我们知道,Java的内存有堆内存、栈内存和字符串常量池等等,其中堆内存是占用内存空间最大的一块,也是Java对象存放的地方,一般我们的数据如果需要从IO读取到堆内存,中间需要经过Socket缓冲区,也就是说一个数据会被拷贝两次才能到达他的的终点,如果数据量大,就会造成不必要的资源浪费。

Netty针对这种情况,使用了NIO中的另一大特性——零拷贝,当他需要接收数据的时候,他会在堆内存之外开辟一块内存,数据就直接从IO读到了那块内存中去,在netty里面通过ByteBuf可以直接对这些数据进行直接操作,从而加快了传输速度。

先看一个 Demo

服务端代码

客服端代码

服务端日志:

客户端日志:

数据传输的载体:ByteBuf

  1. ByteBuf 是一个字节容器,容器里面的的数据分为三个部分,第一个部分是已经丢弃的字节,这部分数据是无效的;第二部分是可读字节,这部分数据是 ByteBuf 的主体数据, 从 ByteBuf 里面读取的数据都来自这一部分; 第三部分的数据是可写字节,所有写到 ByteBuf 的数据都会写到这一段。最后一部分虚线表示的是该 ByteBuf 最多还能扩容多少容量。
  2. 以上三段内容是被两个指针给划分出来的,从左到右,依次是读指针(readerIndex)、写指针(writerIndex),然后还有一个变量 capacity,表示 ByteBuf 底层内存的总容量
  3. 从 ByteBuf 中每读取一个字节,readerIndex 自增1,ByteBuf 里面总共有 writerIndex-readerIndex 个字节可读, 由此可以推论出当 readerIndex 与 writerIndex 相等的时候,ByteBuf 不可读。
  4. 写数据是从 writerIndex 指向的部分开始写,每写一个字节,writerIndex 自增1,直到增到 capacity,这个时候,表示 ByteBuf 已经不可写了。
  5. ByteBuf 里面其实还有一个参数 maxCapacity,当向 ByteBuf 写数据的时候,如果容量不足,那么这个时候可以进行扩容,直到 capacity 扩容到 maxCapacity,超过 maxCapacity 就会报错。

Demo 自定义处理逻辑

服务端

自定义处理器

客户端

自定义处理器

pipeline与channelHandler

  通过上面的一些实战,可以发现我们所有的逻辑代码都写在了一个Handler类里面,幸好现在需要处理的业务不是很多。如果以后功能拓展,这个类会变得非常臃肿。Netty中的pipeline和channelHandler就是解决这个问题的,它们通过责任链设计模式来组织代码逻辑,并且能够支持逻辑的添加和删除,能够支持各类协议拓展,如HTTP、Websocket等。可以看看Netty实战博客中的初始化器类,里面就是通过pipeline添加了各类协议和一些逻辑代码。

pipeline与channelHandler的构成

我们知道一个连接对应一个channel,这个channel的所有处理逻辑在一个ChannelPipeline对象里,就是上图中的pipeline,这是它的对象名。然后这个对象里面是一个双向链表结构,每个节点是一个ChannelHandlerContext对象。这个对象能拿到与channel相关的所有上下文信息,这个对象还包含一个重要的对象:ChannelHandler,它的分类如下。

简单地说,它包含两个接口和这两个接口的实现类,图中左边的实现类是不是很熟悉,就是我们自己写的逻辑处理器里的继承的类。从名字就可以看出,它们的作用分别是读数据和写数据,或理解为入站和出战。最重要的两个方法分别为channelRead():消息入站。和write():消息出战。

参印象笔记:██【好啊】Netty入门与实战教程

Netty 在 xxl-job 中的使用

xxl-job 中的执行器会创建一个 netty server 来接收调度中心的 http “调度请求”:

码先生
Author: 码先生

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注