其他分享
首页 > 其他分享> > 《Netty实战》总结

《Netty实战》总结

作者:互联网

前言

我们都知道Netty是一款用于创建高性能网络应用程序的高级框架,但是实际工作中真正地去直接使用Netty的场景好像不多(反正我没有)。其实Netty无处不在,很多中间件底层通信框架用的都是Netty,dubbo、rocketMQ、Elasticsearch等常用的框架和中间件其实都用到了Netty。最近在读《Netty实战》这本书,做一个知识点的简要概括吧,省略了一些章节(比如Netty用于单元测试等)。

异步和事件驱动

bio线程模型:

nio线程模型:

Netty 的核心组件

Netty的组件和设计

Netty网络抽象的代表

  1. EmbeddedChannel
  2. LocalServerChannel
  3. NioDatagramChannel
  4. NioSctpChannel
  5. NioSocketChannel

ChannelHandler 和 ChannelPipeline

传输

分类

  1. OIO——阻塞传输
  2. NIO——异步传输
  3. Local——JVM 内部的异步通信
  4. Embedded——测试你的ChannelHandler

channel

数据容器ByteBuf

优点

  1. 可以被用户自定义的缓冲区类型扩展
  2. 通过内置的复合缓冲区类型实现了透明的零拷贝
  3. 容量可以按需增长(类似于 JDK 的 StringBuilder)
  4. 在读和写这两种模式之间切换不需要调用 ByteBuffer 的 flip()方法
  5. 读和写使用了不同的索引
  6. 支持方法的链式调用
  7. 支持引用计数
  8. 支持池化

ByteBuf使用模式

  1. 堆缓冲区,支撑数组
  2. 直接缓冲区
  3. 复合缓冲区

字节级操作

  1. 丢弃字节:discardReadBytes()
  2. 索引复位:clear()
  3. 切片:slice();副本:copy()

重要的类

  1. ByteBufHolder,持有ByteBuf引用,可以存储额外信息
  2. ByteBufAllocator,获取池化ByteBuf,可以从Channel或者ChannelHandlerContext获取ByteBufAllocator的引用
  3. Unpooled,获取未池化ByteBuf
  4. ByteBufUtil,工具类

引用计数

ReferenceCounted接口

ChannelHandler和ChannelPipeline

public class DiscardHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ReferenceCountUtil.release(msg); 
    }
}

资源管理

  1. 每当通过调用 ChannelInboundHandler.channelRead()或者 ChannelOutboundHandler.write()方法来处理数据时,都需要确保没有任何的资源泄漏。除非调用了ChannelHandlerContext.fireChannelRead()交给下一个处理器处理。
  2. ChannelOutboundHandler.write()不仅要释放资源,还要通知ChannelPromise。否则可能会出现 ChannelFutureListener 收不到某个消息已经被处理了的通知的情况。
  3. 资源泄露检测类——ResourceLeakDetector
    利用了JDK的虚引用,配置参数java -Dio.netty.leakDetectionLevel=ADVANCED

ChannelPipeline接口

  1. 每一个新创建的 Channel 都将会被分配一个新的 ChannelPipeline。这项关联是永久性的; Channel 既不能附加另外一个 ChannelPipeline,也不能分离其当前的。在 Netty 组件 的生命周期中,这是一项固定的操作,不需要开发人员的任何干预。
  2. ChannelInboundHandler从头部开始处理,ChannelOutboundHandler从尾部开始处理

ChannelHandlerContext接口

  1. ChannelHandlerContext 有很多的方法,其中一些方法也存在于 Channel 和 Channel- Pipeline 本身上,但是有一点重要的不同。如果调用 Channel 或者 ChannelPipeline 上的这 些方法,它们将沿着整个 ChannelPipeline 进行传播。而调用位于 ChannelHandlerContext 上的相同方法,则将从当前所关联的 ChannelHandler 开始,并且只会传播给位于该 ChannelPipeline 中的下一个能够处理该事件的 ChannelHandler。
  2. 重要组件之间的关系
  3. 事件传播

异常处理

EventLoop和线程模型

类层次结构

EventLoop实现细节

  1. 执行逻辑
  2. 分配方式

引导

Bootstrap——客户端或无连接协议

ServerBootstrap——服务端

DatagramChannel——无连接

Bootstrap bootstrap = new Bootstrap();
bootstrap.group(new OioEventLoopGroup()).channel(
OioDatagramChannel.class).handler(new SimpleChannelInboundHandler<DatagramPacket>(){
    @Override
    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
        // Do something with the packet
    }
);}
ChannelFuture future = bootstrap.bind(new InetSocketAddress(0));
future.addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture channelFuture) throws Exception {
        if (channelFuture.isSuccess()) {
            System.out.println("Channel bound");
        } else {
            System.err.println("Bind attempt failed");
            channelFuture.cause().printStackTrace(); 
        }
}); 

关闭

  1. 它将处理任何挂起的事件和任务,并且随后释放所有活动的线程

编解码器

编码器操作出站数据,而解码器处理入站数据。编解码器中的引用计数是会自动处理的,ReferenceCountUtil.release(message)

解码器

  1. ByteToMessageDecoder
  2. ReplayingDecoder
  3. MessageToMessageDecoder
  4. TooLongFrameException 防止解码器缓冲的数据耗尽内存

编码器

  1. MessageToByteEncoder
  2. MessageToMessageEncoder

编解码器

  1. ByteToMessageCodec
  2. MessageToMessageCodec
  3. CombinedChannelDuplexHandler

预置的 ChannelHandler 和编解码器

SslHandler

在大多数情况下,SslHandler将是ChannelPipeline中的第一个ChannelHandler。 这确保了只有在所有其他的 ChannelHandler 将它们的逻辑应用到数据之后,才会进行加密。

HTTP 解码器、编码器和编解码器

  1. HttpRequestEncoder
  2. HttpResponseEncoder
  3. HttpRequestDecoder
  4. HttpResponseDecoder
  5. HttpObjectAggregator——聚合 HTTP 消息
  6. HttpContentCompressor && HttpContentDecompressor——HTTP 压缩和解压

WebSocketProtocolHandler

空闲的连接和超时

  1. IdleStateHandler——可以用来实现心跳
  2. ReadTimeoutHandler
  3. WriteTimeoutHandler

基于分隔符的协议

  1. DelimiterBasedFrameDecoder
  2. LineBasedFrameDecoder——比DelimiterBasedFrameDecoder效率高

基于长度的协议

LineBasedFrameDecoder

  1. FixedLengthFrameDecoder
  2. LengthFieldBasedFrameDecoder

写大型数据

  1. FileRegion
  1. ChunkedWriteHandler

序列化数据

  1. JBoss Marshalling
  2. Protocol Buffers

扩展——研究Netty中碰到的思考

  1. netty解决的epoll空轮询
  2. FastThreadLocal实现原理
  3. EventLoopGroup分配EventLoop的实现细节

类似于轮询,用原子变量来实现索引递增,做了一个优化,如果总数是2的倍数,会通过位移来计算余数

  1. ChannelProgressivePromise实时获取传输进度怎么实现
  2. 流量整形 ChannelTrafficShapingHandler 和 GlobalTrafficShapingHandler
  3. 链路空闲检测 IdleStateHandler

本文由博客一文多发平台 OpenWrite 发布!

Forest441 发布了7 篇原创文章 · 获赞 4 · 访问量 10万+ 私信 关注

标签:实战,Netty,ChannelHandler,ChannelPipeline,ChannelHandlerContext,总结,ByteBuf,Channel
来源: https://blog.csdn.net/Forest441/article/details/104430508