Netty-learn

.1. Netty-learn

.1.1. Gerneral

.1.1.1. Nio buffer

  1. capacity 总数量
  2. limit 用于限制读写
  3. position 下一个读写位置
  4. https://www.bilibili.com/video/av33707223?p=37 节 去掉buffer.clear()注释掉后分析
  5. position<limit<capacity

.1.1.2. Nio网络基本流程

  1. selector 办事大厅
  2. 获取ServerSocketChannel
  3. 设置ServerSocketChannel 属性(是否阻塞)
  4. 获取ServerSocket
  5. 给ServerSocket绑定端口
  6. 将通道注册到selector
  7. 循环selecor
  8. 获取selectorKey
  9. 判断selectorKey类型返回channel
  10. 处理
  11. 移除selectorKey

.1.1.3. Zero copy

  1. 缺少由user model缓存到system kernel缓存;由system kernel缓存到user model缓存下内容拷贝2次 (用户态优化)
  2. System kernel下kernel buffer到socket buffer内容拷贝改为文件描述符拷贝
  3. FileChannel transferto transferFrom 使用零拷贝

.1.1.4. Reactor设计模式

  1. Handle(句柄和描述符,产生事件):本质表示一种资源,该资源(如何写入,写出)可表示一个个事件。
  2. Synchronous Evnet demultiplexer(同步事件分离器):它本身是一个系统调用,用于等待事件的发生(事件可能一个,多个),调用方在调用它的时候会被阻塞,一直阻塞到同步事件分离器上有事件产生为止,位于linux来说,同步事件分离器就是常用的I/O多路复用机制,比如说select,poll,epoll等,在Java NIO中,同步事件分离器对于组件selector,对于的阻塞方法select。
  3. Event Handler(事件处理器):本身由多个回调方法构成,这些回调方法构成了与应用相关的对于某个事件的反馈机制。java NIO中没有,netty中有(比如SimpleChannelInBand,SimpleChanneloutBand)
  4. Concrete Event Handler(具体事件处理器):它是事件处理器的实现 ,从而实现特定的逻辑(比如自己写的MyHandler)
  5. Initation Dispatcher(初始分发器):实际上就是Reactor角色,它本身定义了一些规范,这些规范用于控制事件的调度方式,同时又是提供了应用进行事件处理器的注册,删除等,它本身是整个事件处理器的核心所在,initiaion dispathcer会通过同步事件分离器来等待事件的发生,一旦事件发生,Initation Dispatcher首先会分离出每一个事件,然后调用事件处理器,最后调用相关的回调函数来处理这些事件。

.1.1.5. NioEventLoopGroup

  1. NioEventLoopGroup extends MultithreadEventLoopGroup ,初始化时需要传入线程数(defalt=Math.max(1, SystemPropertyUtil.getInt(
    “io.netty.eventLoopThreads”, Runtime.getRuntime().availableProcessors() * 2)))
  2. 线程数大小极为EventExecutor 数组大小
  3. EventLoopGoup包含多个EventLoop
  4. 一个EventLoop在他整个生命周期中都只会与唯一的一个Thread进行绑定
  5. 所有的EventLoop所处理的各种I/O事件都将在它所关联的Thread上处理
  6. 一个channel在它的整个生命周期中只会注册在一个EventLoop上
  7. 一个EventLoop在运行过程中,会被分配给一个或多个channel(多个channel会被注册到一个Selector上)
  8. handler中业务是单线程执行,不需要并发控制,因此不能做耗时操作
  9. Channel的实现一定是线程安全的,因此,我们可以存储一个channel 引用,并且在需要向远端发送数据时,通过这个引用来调用channel相关的方法,即使当时有很多线程都在使用它也不会出现多线程问题,而且。消息一定会按照顺序发送出去
  10. 在业务开发中,不要将长时间执行的耗时任务放置到EventLoop的执行队列中,因此它会一直阻塞该线程所对于的所有channel上的其他执行任务,如果我们需要阻塞调用或耗时操作,那么我们需要使用一个专门的EventExcutor(业务线程池)
  • 使用 java eventExcutor
  • 借助pipeline中添加channelHandler调用的addLast(group , handler)

.1.1.6. Netty 组件间关系

  1. main Reactor 和 sub Reactor分别对于netty 中的bossGroup 和workGroup,selector 对于EventLoop
  2. ChannelInitializer(采用模板模式) 继承 ChannelInboundHandlerAdapter 继承 ChannelHandlerAdapter并且实现了ChannelInboundHandler接口,这里采用适配器模式(将ChannelHandlerContext(两空) 转化成ChannelInboundHandler(三空)接口)。以上是ChannelHandler接口转换
  3. ChannelPipline 中存放ChannelHandler,包含InBoundHandler和OutBoundHandler
  4. Channel中可以获取其对于的ChannelPipline ,ChannelPipline 也关联着唯一的Channel
  5. ChannelHandlerContext 何以获取channel ChannelHandler ChannelPipline ,自身通过双向链表存储
  6. 对于netty消息发送方式,写入到channel中的消息会从末尾开始流动,写入ChannelHandlerContext将会从ChannelPipeline中下一个ChannelHandler开始流动

.1.1.7. Netty处理器

  1. netty处理器包含入栈处理器和出栈处理器
  2. 入栈处理器顶层ChannelInboundHandler 出栈处理器顶层ChannelOutboundHandler
  3. 编码:message -> byte(ChannelOutboundHandler) 解码:byte -> message(ChannelInboundHandler)
  4. ReplayingDecoder extends ByteToMessageDecoder 会不断重试判断读取是否满足,因此不需要数据读取大小判断

.1.1.8. Tcp的黏包,拆包

  1. 黏包:tcp 在传输消息时,可能数据不够发送条件,需要合并消息
  2. 拆包:tcp 在数据接受时候,可能会收到多个消息合并后的数据包
  3. netty 提供前一条消息与下一条消息分割的分割符号识别

.1.1.9. Future

  1. JDK提供的Future只能通过手工方式检查结果,而这个操作是会阻塞的;Netty则对ChannelFuture进行了增强,通过ChannelFutrueListener以回调方式来获取执行结果,去除了手工检查阻塞的操作,值得注意的是:ChannelFutureListener的OperationComplete方法是由I/O线程执行的,因此要注意的是不要在这里执行耗时操作,否则需要通过另外的线程或线程池来执行