笔者看来Netty的内核主要包括如下图三个部分:

其各个核心模块主要的职责如下:

  • 内存管理
    主要提高高效的内存管理,包含内存分配,内存回收。

  • 网通通道
    复制网络通信,例如实现对NIO、OIO等底层JAVA API 的封装,简化网络编程模型。

  • 线程模型

    提供高效的线程协作模型。

大家不妨回想一下在以往的面试的过程中,面试官通常会问:Netty 的线程模型是什么?

主从多 Reactor 模型,相信大家都能脱口而出,然后呢?就没有然后了?

线程模型在网络通信中主要解决什么样的问题?在 Netty 中又是如何解决的,Netty 的线程模型为什么如此高效?请容我慢慢道来。

温馨提示:为了保证文章观点的严谨性,将探究领域锁定在:Netty NIO 相关。

1、主从多 Reactor 模型


主从多 Reactor 模型是业界一种非常经典的线程编程模型,其原理图如下所示:

我们首先简单介绍一下上图中涉及的几个重要角色:

  • Acceptor

    请求接收者,在实践时其职责类似服务器,并不真正负责连接请求的建立,而只将其请求委托 Main Reactor 线程池来实现,起到一个转发的作用。

  • Main Reactor
    主 Reactor 线程组,主要负责连接事件,并将IO读写请求转发到 SubReactor 线程池。当然在一些需要对客户端进行权限控制等场景下,权限校验的职责可以放到 Main Reactor 线程池,即 Main Reactor 也可以注册通道的读写事件,读取客户端权限校验相关的数据包,执行权限验证,权限验证通过后再将2通道注册到IO线程。

  • Sub Reactor
    Main Reactor 通常监听客户端连接后会将通道的读写转发到 Sub Reactor 线程池中一个线程(负载均衡),负责数据的读写。在 NIO 中 通常注册通道的读(OP_READ)、写事件(OP_WRITE)。

为了更加深刻的理解主从 Reactor 模型,我们来看一下网络通讯一般会包含哪些关键动作:

一个网络交互通常的几个步骤如下:

  • 服务端启动,并在特定端口上监听,例如 web 应用的 80端口。

  • 客户端发起TCP的三次握手,与服务端建立连接,这里以 NIO 为例,连接成功建立后会创建NioSocketChannel对象。

  • 服务端通过 NioSocketChannel 从网卡中读取数据

  • 服务端根据通信协议从二进制流中解码出一个个请求。

  • 根据请求,执行对应的业务操作,例如 Dubbo 服务端接受一个查询用户ID为1的用户信息。

  • 将业务执行结果返回到客户端,通常涉及到协议编码、压缩等。

线程模型需要解决的问题:连接监听、网络读写、编码、解码、业务执行这些操作步骤如何运用多线程编程,提升性能。

主从多Reactor模型是如何解决上面的问题呢?

  1. 连接建立(OP_ACCEPT)由 Main Reactor 线程池负责,创建NioSocketChannel后,将其转发给SubReactor。

  2. SubReactor 线程池主要负责网络的读写(从网络中读字节流、将字节流发送到网络中),即注册OP_READ、OP_WRITE,并且同一个通道会绑定一个SubReactor线程

  3. 编码、解码、业务执行,则具体情况具体分析

    通常编码、解码会放在IO线程中执行,而业务逻辑的执行通常会采用额外的线程池,但不是绝对的,一个好的框架通常会使用参数来进行定制化选择,例如 ping、pong 这种心跳包,直接在 IO 线程中执行,无需再转发到业务线程池,避免线程切换开销。

温馨提示:在网络编程中,通常将用于网络读写的线程称为IO线程。

2、Netty 的线程模型


Netty的线程模型是基于主从多Reactor模型。

Netty 中网络的连接事件(OP_ACCEPT)由Main Reactor 线程组实现,即 Boss Group,通常只需设置一个线程

网络的读写操作由 Work Group ( Sub Reactor) 线程组来实现,线程的个数默认为 2 * CPU Core,一个 Channel 绑定到其中一个 Work 线程,一个 Work 线程中可以绑定多个 Channel

在 Netty 中编码、解码等操作会被封装成一个一个事件处理器(ChannelHandler),那这些 Handler 是在IO线程池中执行?

默认情况下ChannelHandler 是在 IO 线程中执行,那如何改变默认行为呢?其关键代码如下:

关键点:在将事件处理器添加到事件链时可以指定在哪个线程池中执行,如果不指定则为IO线程中执行。

面试官:通常业务操作会专门开辟一个线程池,那业务处理完成之后,如何将响应结果通过 IO 线程写入到网卡中呢?

业务线程调用 Channel 对象的 write 方法并不会立即写入网络,只是将数据放入一个待写入队列(缓存区),然后IO线程每次执行事件选择后,会从待写入缓存区中获取写入任务,将数据真正写入到网络中,数据到达网卡之前会经过一系列的 Channel Handler(Netty事件传播机制),最终写入网卡。

最后再来介绍一下 Netty 中 IO 线程的大体工作流程。

IO线程处理的关键点:

  • 每一IO线程在执行上述操作时是串行执行的,即注册在一个 Selector(事件选择器)中的所有通道,同一时间只有一个通道的事件被处理。这也是为什么NIO应对大文件传输时不具备优势的根本原因。

  • IO 线程在处理完所有就绪事件后,还会从任务队列(Task Queue)获取任务,例如上文中提到的业务线程在执行完业务后需要将返回结果写入网络,Netty 中所有的网络读写操作只能在IO线程中真正获得运行,故业务线程需要将带写入的响应结果封装成 Task,放入到 IO 线程任务队列中。

3、总结


回到到主题,如果我们在面试过程中碰到面试官提问“Netty 的线程模型是什么?”时,我们应该可以从容应对了。

我觉得可以从如下几个方面进行展开。

  1. Netty的线程模型基于主从多Reactor模型。通常由一个线程负责处理OP_ACCEPT事件,拥有 CPU 核数的两倍的IO线程处理读写事件。

  2. 一个通道的IO操作会绑定在一个IO线程中,而一个IO线程可以注册多个通道。

  3. 在一个网络通信中通常会包含网络数据读写,编码、解码、业务处理。默认情况下编码、解码等操作会在IO线程中运行,但也可以指定其他线程池。

  4. 通常业务处理会单独开启业务线程池,但也可以进一步细化,例如心跳包可以直接在IO线程中处理,而需要再转发给业务线程池,避免线程切换。

  5. 在一个IO线程中所有通道的事件是串行处理的。

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

面试官:Netty的线程模型可不是Reactor这么简单相关推荐

  1. 【Netty】Netty 简介 ( 原生 NIO 弊端 | Netty 框架 | Netty 版本 | 线程模型 | 线程 阻塞 IO 模型 | Reactor 模式引入 )

    文章目录 一. NIO 原生 API 弊端 二. Netty 简介 三. Netty 架构 四. Netty 版本 五. Netty 线程模型 六. 阻塞 IO 线程模型 七. 反应器 ( React ...

  2. java基础巩固-宇宙第一AiYWM:为了维持生计,Redis基础Part6(Redis的应用场景、Redis是单线程的速度还快、Redis线程模型:Reactor模式、事件、发布订阅、管道)~整起

    PART1-1:为什么Redis是单线程的 Redis单线程是指: Redis的网络IO和键值对读写是由一个线程来完成的.这也是 Redis 对外提供键值存储服务的主要流程.Redis的其他功能,比如 ...

  3. Netty之线程模型

    Reactor 线程模型: Reactor 是反应堆的意思,Reactor 模型是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式.服务端程序处理传入多路请求,并将它们同步分派给请 ...

  4. 写屏障是什么_面试官为什么问内存模型总离不开final关键字,该如何应对?

    Java 语言的每个关键字都设计的很巧妙,金雕玉琢,只有深度钻研其中,才知其中懊悔,本文带领大家一起深入理解 Java 内存模型之 final. 加我微信好友的不要着急,手机没电了,等我借个充电器之后 ...

  5. JavaSocket编程之Netty框架线程模型

    1.Netty概述 Netty是一个由JBoss提供的高效的Java NIO client-server(客户端-服务器)开发框架,使用Netty可以快速开发网络应用.Netty提供了一种新的方式来使 ...

  6. Linux后端服务器网络编程之线程模型丨reactor模型详解

    前言   上一篇文章<后端服务器网络编程之 IO 模型>中讲到服务器端高性能网络编程的核心在于架构,而架构的核心在于进程/线程模型的选择.本文将主要介绍传统的和目前流行的进程/线程模型,在 ...

  7. 面试官:Java 线程如何启动的?

    摘要:Java 的线程创建和启动非常简单,但如果问一个线程是怎么启动起来的往往并不清楚,甚至不知道为什么启动时是调用start(),而不是调用run()方法呢? 本文分享自华为云社区<Threa ...

  8. 跟面试官谈【线程池】

    目录 What? Why? 分类? 1. newCachedThreadPool 1.1.what? 1.2 代码实例 1.3 执行结果 1.4 源码分析 1.5 缺点 2.newFixedThrea ...

  9. 求职者提问的问题面试官不会_如何通过三个简单的问题就不会陷入求职困境

    求职者提问的问题面试官不会 by DJ Chung 由DJ Chung 如何通过三个简单的问题就不会陷入求职困境 (How to get un-stuck in your job search wit ...

最新文章

  1. hp unix oracle rac节点一磁盘损坏,节点修复
  2. c语言怎么写到单片机里,哪位师傅知道51单片机怎样编写子程序?C语言的。在主程序里调...
  3. 2021-9-下旬 数据结构-线性表-链表-java代码实现(复习用)
  4. 闪存技术论坛即将召开 产业链领军企业齐聚谈变革
  5. 京东三级列表页持续架构优化—Golang+Lua(OpenResty)最佳实践
  6. Eclipse 各种快捷键
  7. [HNOI2015] 接水果(倍增 + 整体二分)
  8. 报错,null [java.lang.IndexOutOfBoundsException,Index: 5, Size: 5]
  9. linux shell常用函数,ps
  10. 软件测试管理—如何写好软件测试计划书
  11. 创建虚拟机并加载镜像文件
  12. 如何识别英文单词java,自动识别英文单词显示(Android+Java)
  13. R语言结构方程模型(SEM)在生态学领域中的实践应用
  14. ReactNative 刘海屏适配iPhoneX
  15. 软件工程课程周学习进度报告——第三周
  16. TOEFL-Listen-课堂笔记
  17. 边缘检测之Robert算子
  18. 学IT技术有必要报培训班吗?
  19. BootStra相关脚本引用说明
  20. 《Adobe Photoshop CS5中文版经典教程(全彩版)》—第1课1.4节在Photoshop中还原操作...

热门文章

  1. syslog 华为 服务器_删除华为云服务器自带的探针
  2. html打开时按钮自动触发事件,html在用户按下按键时触发的事件属性onkeydown
  3. linux中命令对c文件进行编译,Linux下C语言编译基础及makefile的编写
  4. linux6.5怎样安装vim,在Centos 6.5下成功安装和配置了vim7.4
  5. 江苏省有JAVA技能大赛,江苏省职业学校技能大赛组委会
  6. 操作系统之进程管理:17、死锁
  7. 6-6-2:STL之map和set——map的基本使用
  8. 100万并发连接服务器笔记之处理端口数量受限问题
  9. linux操作系统中文件系统管理--实训
  10. sqlmap --os-shell反制小思路