|
|
@ -14,13 +14,80 @@
|
|
|
|
-
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
|
|
## Netty基本组件
|
|
|
|
## Netty基本组件
|
|
|
|
|
|
|
|
- Netty对传统 Socket 进行封装
|
|
|
|
- NioEventLoop,Channel,ByteBuf,Pipeline,ChannelHandler
|
|
|
|
- NioEventLoop,Channel,ByteBuf,Pipeline,ChannelHandler
|
|
|
|
|
|
|
|
![Netty组件对应](pic/Netty组件对应关系.png)
|
|
|
|
|
|
|
|
- NioEventLoop => Thread(监听客户端的连接 + 处理每个连接的读写线程)
|
|
|
|
|
|
|
|
- Channel => Socket 对一条连接的封装
|
|
|
|
|
|
|
|
- ByteBuf => IO Bytes 每一个Channel上数据流的处理
|
|
|
|
|
|
|
|
- Pipeline => Logic Chain 逻辑处理链
|
|
|
|
|
|
|
|
- Channel Handler => Logic 每一个逻辑
|
|
|
|
|
|
|
|
|
|
|
|
## Netty服务端启动
|
|
|
|
## Netty服务端启动
|
|
|
|
- 分析服务端启动流程,包括服务端Channel的创建,初始化,以及注册到selector
|
|
|
|
- 分析服务端启动流程,包括服务端Channel的创建,初始化,以及注册到selector
|
|
|
|
|
|
|
|
- 服务端的启动在哪里初始化?
|
|
|
|
|
|
|
|
- 在哪里accept连接?
|
|
|
|
|
|
|
|
- 启动过程
|
|
|
|
|
|
|
|
- 创建服务端 Channel -> newChannel()
|
|
|
|
|
|
|
|
- 初始化服务端 Channel -> init()
|
|
|
|
|
|
|
|
- 注册 selector -> register()
|
|
|
|
|
|
|
|
- 端口绑定 -> doBind()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
- 源码分析1 - 创建服务端Channel
|
|
|
|
|
|
|
|
- bind()[用户代码入口] -> initAndRegister()[初始化并注册] -> newChannel()[创建服务端channel]
|
|
|
|
|
|
|
|
- 反射创建服务端Channel : NioServerSocketChannel()[构造函数] -> newSocket()[通过jdk来创建底层jdk channel] -> NioServerSocketChannelConfig()[tcp参数配置类] -> AbstractNioChannel() ->
|
|
|
|
|
|
|
|
- configureBlocking(false)[阻塞模式] -> AbstractChannel()[创建id, unsafe, pipeline]
|
|
|
|
|
|
|
|
- 源码分析2 - 初始化服务端Channel
|
|
|
|
|
|
|
|
- init()[初始化入口] -> set ChannelOptions, ChannelAttrs [这个配置用的不多] -> set ChildOptions,ChildAttrs [每次创建的新连接都会把这两个属性配置上去] -> config handler[配置服务端pipeline] ->
|
|
|
|
|
|
|
|
- add ServerBootstrapAcceptor[添加连接器,默认添加特殊的Handler]
|
|
|
|
|
|
|
|
- 源码分析3 - 注册 selector
|
|
|
|
|
|
|
|
- AbstractChannel.register(channel)[入口] -> this.eventLoop = eventLoop[绑定线程] -> register0()[实际注册] -> doRegister()[调用jdk底层注册] -> invokeHandlerAddedIfNeeded()[做一些事件的回调] ->
|
|
|
|
|
|
|
|
- fireChannelRegistered()[传播事件]
|
|
|
|
|
|
|
|
- 源码分析4 - 端口绑定
|
|
|
|
|
|
|
|
- AbstractUnsafe.bind()[入口] -> doBind() -> javaChannel().bind()[jdk底层绑定] -> pipeline.fireChannelActive()[传播事件] -> HeadContext.readIfIsAutoRead()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## NioEventLoop
|
|
|
|
## NioEventLoop
|
|
|
|
- 分析Netty reactor线程处理过程,包括事件监听,事件处理,常规任务处理和定时任务处理
|
|
|
|
- 分析Netty reactor 线程处理过程,包括事件监听,事件处理,常规任务处理和定时任务处理
|
|
|
|
|
|
|
|
- 问题:
|
|
|
|
|
|
|
|
- 默认情况下, Netty 服务端启多少线程? 何时启动?
|
|
|
|
|
|
|
|
- Netty是如何解决jdk空轮询Bug的?会导致CPU飙升到100%
|
|
|
|
|
|
|
|
- Netty是如何保证异步串行无锁化?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
- NioEventLoop 创建
|
|
|
|
|
|
|
|
- new NioEventLoopGroup()[线程组, 默认2*CPU] -> new ThreadPerTaskExecutor()[线程创建器] -> for(){new Child()}[循环构造NioEventLoop对象数组] ->
|
|
|
|
|
|
|
|
- chooserFactory.newChooser()[线程选择器:给每个新连接分配NioEventLoop线程]
|
|
|
|
|
|
|
|
- 深入剖析 ThreadPerTaskExecutor()
|
|
|
|
|
|
|
|
- 每次执行任务都会创建一个线程实体 -> FastThreadLocalThread
|
|
|
|
|
|
|
|
- NioEventLoopGroup 线程命名规则 nioEventLoop-1-xx
|
|
|
|
|
|
|
|
- 深入剖析 newchild()
|
|
|
|
|
|
|
|
- 保存线程执行器 ThreadPerTaskExecutor
|
|
|
|
|
|
|
|
- 创建一个 MpscQueue
|
|
|
|
|
|
|
|
- 创建一个 selector
|
|
|
|
|
|
|
|
- 深入剖析 chooserFactory.newChooser() 创建线程选择器
|
|
|
|
|
|
|
|
- chooserFactory.newChooser() -> isPowerOfTwo()[判断是否是2的幂, 如2,4,8,16] ->[TRUE] PowerOfTwoEventExecutorChooser[优化] -> index++ & (length-1) ->
|
|
|
|
|
|
|
|
- [FALSE] GenericEventExecutorChooser[普通] -> abs(index++ % length)
|
|
|
|
|
|
|
|
- ps: 计算机底层 & 操作比 取模操作高效的多, &操作是二进制的操作
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
- NioEventLoop 启动触发器
|
|
|
|
|
|
|
|
- 服务端启动绑定端口
|
|
|
|
|
|
|
|
- 新连接接入通过 chooser 绑定一个 NioEventLoop
|
|
|
|
|
|
|
|
- 启动流程
|
|
|
|
|
|
|
|
- bind() -> execute(task)[入口] -> startThread() -> doStartThread()[创建线程] -> ThreadPerTaskExecutor.execute()[线程执行器进行创建] ->
|
|
|
|
|
|
|
|
- thread = Thread.currentThread()[保存创建的线程] -> NioEventLoop.run()[启动]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
- NioEventLoop 执行逻辑
|
|
|
|
|
|
|
|
- NioEventLoop.run() -> for(;;) -> select()[检查是否有io事件] -> processSelectedKeys()[处理io事件] -> runAllTasks()[处理异步任务队列]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
- select() 方法执行逻辑 - 检测IO事件
|
|
|
|
|
|
|
|
- deadline 以及任务穿插逻辑处理
|
|
|
|
|
|
|
|
- 阻塞式的 select
|
|
|
|
|
|
|
|
- 解决 jdk 空轮训的 bug
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 新连接接入
|
|
|
|
## 新连接接入
|
|
|
|
- 分析新连接接入以及绑定reactor线程,绑定到selector的过程
|
|
|
|
- 分析新连接接入以及绑定reactor线程,绑定到selector的过程
|
|
|
|