vlambda博客
学习文章列表

突击大厂面试的Netty源码知识(下)

阅读本文约“10分钟”

适读人群:Java中级


6.1快乐,曾经的少年


攝影師:Nataliya Vaitkevich,連結:Pexels


ButeBuf

1.ByteBuffer的缺点

    长度固定,容量不能动态扩展、收缩,遇到大的POJO会出现索引越界异常

    只有一个标识指针position,需要手动调用flip和rewind


2.实现策略

    基于JDK ByteBuffer,增加额外的功能,解决原有ByteBuffer的缺点

    聚合JDK ByteBuffer,通过Facade模式对其进行包装,可以减少自身的代码量,降低实现成本


3.读写操作

    读操作使用readerIndex、写操作使用writerIndex


4.自动扩容

    put操作对剩余空间进行校验,不足则创建新的ByteBuffer,并对之前的ByteBuffer复制到新创建的ByteBuffer,释放ByteBuffer


5.内存分类

    堆内存(HeapByteBuf):内存的分配和回收速度快,可以被JVM自动回收,缺点:进行Socket的I/O读写,需要额外复制一次,将堆内存对应的缓冲区复制到内核Channel

    直接内存(DirectByteBuf):非堆内存,相比堆内存,他的分配和回收速度会慢一些,但是将他写入socket,由于少了一次内存复制,速度比堆内存快


6.最佳实践

    在I/O通信线程的读写缓冲区使用DirectByteBuf,后端业务消息的编解码模块使用HeapByteBuf,可以达到性能最优


注意:推荐使用基于内存的ByteBuf,但是内存池的管理和维护更加复杂,使用起来需要谨慎


Channel和Unsafe

1.Channel

    Netty自己的Channel,用于异步I/O操作和其他相关的操作


2.Unsafe

    内部接口,聚合在Channel中协助进行网络读写的相关操作,不应该被上层使用者调用


3.Channel设计理念

    采用Facade模式进行统一封装,将网络I/O操作等封装,统一对外提供

    接口定义大而全,提供与socketchannel、serversocketchannel统一的视图,由不同的子类实现不同的功能,公共功能在抽象父类中实现,最大程度地实现功能和接口的重用

    采用聚合而非包含的方式,统一负责分配和调度


4.Unsafe功能

    I/O读写操作由其完成


ChannelPipeline和ChannelHandler

其类似Servlet和Filter过滤器,这类拦截器实际上式职责链模式的一种变形,主要是为了方便事件的拦截和用户业务逻辑的定制


1.ChannelPipeline主要特性

    支持运行态动态的添加/删除ChannelHandler,如业务高峰进行拥塞保护ChannelHandler的添加,高峰期结束后则删除

    ChannelPipeline是线程安全的,不存在多线程并发问题,但是ChannelHandler不是线程安全,用户需要保证自己的ChannelHandler线程安全


2.ChannelHandler功能说明

    负责I/O事件或者I/O操作进行拦截和处理,它可以选择性地拦截和处理自己感兴趣的事件,也可以透传和终止事件的传递


3.ChannelHandler分类

    Pipeline系统的,用户不可预见,HeadHandler、TailHandler

    编解码Handler

    系统功能性,流量整型Handler、读写超时Handler、日志Handler


EventLoop和EventLoopGroup

1.Reactor单线程模型

    所有I/O操作都在同一个NIO线程上完成(异步非阻塞)

    面对高负载、大并发不合适

        (1)性能无法支撑

        (2)负载过重,处理速度变慢,导致消息积压和处理超时,成为系统瓶颈

        (3)可靠性问题,一坏就全坏


2.Reactor多线程模型

    比起单线程,多出一组NIO线程来处理I/O操作

    一个NIO处理Acceptor线程监听服务端,接受客户端的连接请求

    网络操作读写由一个NIO线程池处理,采用标准的JDK线程池,一个任务队列和N个线程

    一个NIO线程处理多条连理,一个链路只对应一个NIO线程


3.主从Reactor多线程模型

    服务端接收客户端连接是一个独立的NIO线程池

    可以解决一个服务端监听线程无法有效处理所有客户端连接的性能不足问题,官方推荐


Future和Promise

1.Future用于获取异步操作的结果

2.ChannelFuture有两种状态:uncompleted和completed

3.异步I/O操作的超时

    TCP层面的I/O超时

    业务逻辑层面的操作超时

4.Promise是可写的Future,Future自身并没有写操作的接口

5.Netty通过Promise对Future进行扩展,用于设置I/O操作的结果

6.可能存在I/O和用户同时操作Promise,设置结果时需要加锁保护,防止并发操作