一、BIO、NIO 和 AIO


【1】阻塞 IO(Blocking I/O):同步阻塞I/O模式,当一条线程执行 read() 或者 write() 方法时,这条线程会一直阻塞直到读取一些数据或者写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。但是,当面对十万甚至百万级连接的时候,传统的 BIO模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。

【2】非阻塞 NIO(New I/O):NIO是一种同步非阻塞的 I/O模型,NIO 与原有的 IO 有同样的作用和目的,但是使用的方式完全不同,NIO 支持面向缓冲区、基于通道的操作。NIO 将以更加高效的方式进行文件读写操作。JAVA NIO的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO系统,需要获取用于连接 IO设备的通道以及用于容纳数据的缓冲区。对数据进行处理。阻塞IO 会一直等待,所以非阻塞IO 是用来解决 IO线程与 Socket 之间的解耦问题【通过引入事件机制】,如果 Socket 发送缓冲区可写的话会通知 IO线程进行 write,如果 Socket 的接收缓冲区可读的话会通知 IO线程进行 read。NIO 提供了与传统 BIO 模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel。对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

【3】I/O 复用模型:非阻塞 IO中引入的机制就是 IO多路复用模型,Linux 提供了 epoll系统调用,epoll使用基于事件驱动方式代替顺序扫描(select/poll),因此性能更高。当有fd 就绪时,立即回调函数 rollback。IO多路复用技术底层就是通过 epoll 函数实现的。

【4】AIO (Asynchronous I/O):AIO 也就是 NIO2。在 Java 7 中引入了 NIO 的改进版 NIO2,它是异步非阻塞的IO模型。异步 IO 是基于事件回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO 的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

二、Netty 的各大组件


【1】Channel:Channel 是 Netty 网络操作抽象类,它除了包括基本的 I/O 操作,如 bindconnectreadwrite 之外,还包括了 Netty 框架相关的一些功能,如获取该 Channel 的 EventLoop。在传统的网络编程中,作为核心类的 Socket ,它对程序员来说并不是那么友好,直接使用其成本还是稍微高了点。而 Netty 的 Channel 则提供的一系列的 API ,它大大降低了直接与 Socket 进行操作的复杂性。而相对于原生 NIO 的 Channel,Netty 的 Channel 具有如下优势: ①、在 Channel 接口层,采用  Facade 模式进行统一封装,将网络 I/O 操作、网络 I/O 相关联的其他操作封装起来,统一对外提供。②、Channel 接口的定义尽量大而全,为 SocketChannel 和 ServerSocketChannel 提供统一的视图,由不同子类实现不同的功能,公共功能在抽象父类中实现,最大程度地实现功能和接口的重用。③、具体实现采用聚合而非包含的方式,将相关的功能类聚合在 Channel 中,有 Channel 统一负责和调度,功能实现更加灵活。

【2】EventLoop:Netty 基于事件驱动模型,使用不同的事件来通知我们状态的改变或者操作状态的改变。它定义了在整个连接的生命周期里当有事件发生的时候处理的核心抽象。Channel 为 Netty 网络操作抽象类,EventLoop 主要是为 Channel 处理 I/O 操作,两者配合参与 I/O 操作。ChannelEventLoopThreadEventLoopGroup之间的关系:
  ①、一个 EventLoopGroup 包含一个或多个 EventLoop
  ②、一个 EventLoop 在它的生命周期内只能与一个 Thread绑定。
  ③、所有 EnventLoop 处理的 I/O事件都将在它专有的 Thread 上被处理
  ④、一个 Channel 在它的生命周期内只能注册于一个 EventLoop
  ⑤、一个 EventLoop 可被分配至一个或多个 Channel
当一个连接到达时,Netty 就会注册一个 Channel,然后从 EventLoopGroup 中分配一个 EventLoop 绑定到这个Channel上,在该 Channel的整个生命周期中都是有这个绑定的 EventLoop 来服务的。

【3】ChannelFuture:Netty 为异步非阻塞,即所有的 I/O 操作都为异步的,因此,我们不能立刻得知消息是否已经被处理了。Netty 提供了 ChannelFuture 接口,通过该接口的 addListener() 方法注册一个 ChannelFutureListener,当操作执行成功或者失败时,监听就会自动触发返回结果。

【4】ChannelHandler:ChannelHandler 为 Netty 中最核心的组件,它充当了所有处理入站出站数据的应用程序逻辑的容器。ChannelHandler 主要用来处理各种事件,这里的事件很广泛,比如可以是连接数据接收异常数据转换等。ChannelHandler 有两个核心子类 ChannelInboundHandler ChannelOutboundHandler,其中 ChannelInboundHandler 用于接收、处理入站数据和事件,而 ChannelOutboundHandler 则相反。

【5】ChannelPipeline:ChannelPipeline 为 ChannelHandler 链提供了一个容器并定义了用于沿着链传播入站和出站事件流的 API。一个数据或者事件可能会被多个 Handler 处理,在这个过程中,数据或者事件经流 ChannelPipeline,由 ChannelHandler 处理。在这个处理过程中,一个 ChannelHandler 接收数据后处理完成后交给下一个 ChannelHandler,或者什么都不做直接交给下一个 ChannelHandler。当一个数据流进入 ChannlePipeline 时,它会从 ChannelPipeline 头部开始传给第一个 ChannelInboundHandler ,当第一个处理完后再传给下一个,一直传递到管道的尾部。与之相对应的是,当数据被写出时,它会从管道的尾部开始,先经过管道尾部的 “最后” 一个ChannelOutboundHandler,当它处理完成后会传递给前一个 ChannelOutboundHandler 。当 ChannelHandler 被添加到 ChannelPipeline 时,它将会被分配一个 ChannelHandlerContext它代表了 ChannelHandler 和 ChannelPipeline 之间的绑定。其中 ChannelHandler 添加到 ChannelPipeline 过程如下:
①、一个 ChannelInitializer 的实现被注册到了 ServerBootStrap 中;
②、当 ChannelInitializer.initChannel() 方法被调用时,ChannelInitializer 将在 ChannelPipeline 中安装一组自定义的ChannelHandler;
③、ChannelInitializer 将它自己从 ChannelPipeline 中移除;

三、Netty 的线程模型


【博客连接】:链接

四、TCP 粘包/拆包的原因及解决方法


【博客连接】:链接

五、了解哪几种序列化协议?包括使用场景和如何去选择


【博客连接:序列化的缺点】:链接
【博客连接:编辑码框架 Protobuf】:链接
【博客连接:编辑码框架 Thrift】:链接

六、Netty 的零拷贝实现


【博客连接】:链接

七、Netty 的高性能分析


【1】传输:IO 模型在很大程度上决定了框架的性能,相比于BIO,Netty建议采用异步通信模式,因为 NIO一个线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞IO "一连接一线程模型",架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。正如代码中所示,使用的是 NioEventLoopGroup 和 NioSocketChannel 来提升传输效率。
【2】协议:采用什么样的通信协议,对系统的性能极其重要,Netty 默认提供了对 Google Protobuf 的支持,也可以通过扩展Netty 的编解码接口,用户可以实现其它的高性能序列化框架。
【3】线程:Netty 使用了Reactor线程模型,但 Reactor 模型不同,对性能的影响也非常大,上面线程模型中就介绍常用的 Reactor 模型的三种情况。

八、基于BIO实现的Server端,当建立了100个连接时,会有多少个线程?如果基于NIO,又会是多少个线程? 为什么?


BIO由于不是 NIO那样的事件机制,在连接的 IO读取上,无论是否真的有读/写发生,都需要阻塞住当前的线程,对于基于 BIO实现的 Server端,通常的实现方法都是用一个线程去 accept连接,当连接建立后,将这个连接的 IO读写放到一个专门的处理线程,所以当建立100个连接时,通常会产生1个 Accept线程 + 100个处理线程

NIO通过事件来触发,这样就可以实现在有需要读/写的时候才处理,不用阻塞当前线程,NIO在处理 IO的读写时,当从网卡缓冲区读或写入缓冲区时,这个过程是串行的,所以用太多线程处理 IO事件其实也没什么意义,连接事件由于通常处理比较快,用1个线程去处理就可以,IO事件呢,通常会采用 cpu core数+1cpu core数 * 2,这个的原因是 IO线程通常除了从缓冲区读写外还会做些比较轻量的例如解析协议头等,这些是可以并发的,为什么不只用1个线程处理,是因为当并发的 IO事件非常多时,1个线程的效率不足以发挥出多核CPU 的能力,从而导致这个地方成为瓶颈,这种在分布式场景中比较明显,按照这个,也就更容易理解为什么在基于 Netty等写程序时,不要在 IO线程里直接做过多动作,而应该把这些动作转移到另外的线程池里去处理,就是为了能保持好 IO事件能被高效处理。从上面可以看出,对于大多数需要建立大量连接,但并发读写并不会同时产生的场景而言,NIO的优势是非常明显的。这种关于BIO、NIO的问法的变化空间是非常大的,还可以进一步拓展问问AIO和BIO、NIO的根本不同。

九、Netty 的心跳检测及重连机制怎么实现的


【博客连接】:链接

十、ChannelInboundHandlerAdapter 与 SimpleChannelInboundHandler 的区别


【博客连接】:链接

----关注公众号,获取更多内容----

Java面试——Netty的更多相关文章

  1. Java面试通关要点汇总集

    Java面试通关要点汇总集 2018-03-09 转自:Java面试通关要点汇总集 文章目录 1. 基础篇  1.1. 基本功  1.2. 集合  1.3. 线程  1.4. 锁机制2. 核心篇  2 ...

  2. Java面试 32个核心必考点完全解析

    目录 课程预习 1.1 课程内容分为三个模块 1.2 换工作面临问题 1.3 课程特色 课时1:技术人职业发展路径 1.1 工程师发展路径 1.2 常见技术岗位划分 1.3 面试岗位选择 1.4 常见 ...

  3. Java面试大纲-java面试该做哪些准备,java开发达到这样的水平可以涨工资

    Java培训结束,面临的就是毕业找工作.在找工作时,就要针对性地做充分的面试准备.准备不充分的面试,完全是浪费时间,更是对自己的不负责. 上海尚学堂Java培训整理出Java面试大纲,其中大部分都是面 ...

  4. 2019热门JAVA面试问题

    收到不少读者反馈,说自己在应聘一些中大型互联网公司的Java工程师岗位时遇到了不少困惑. 这些同学说自己也做了精心准备,网上搜集了不少Java面试题,然而实际去互联网公司面试才发现,人家问的,和你准备 ...

  5. 【面试题】2018年最全Java面试通关秘籍汇总集!

    [面试题]2018年最全Java面试通关秘籍汇总集!(转载于互联网)   前几天在交流群里有些小伙伴问面试相关的试题,当时给出了一些问题,苦于打字太累就没写下去了,但觉得这是一个很不负责任的表现,于是 ...

  6. Java面试通关要点

    Java面试通关要点 2018-03-23 梁桂钊 占小狼的博客 占小狼的博客 占小狼的博客 微信号 whywhy_zj 功能介绍 Java进阶技术干货.实践分享,跟着狼哥一起学习JVM.性能调优,欢 ...

  7. Java面试必刷常见真题200+ ,让你“过五关,斩六将”,轻松入大厂

    这份面试清单是我从 2015 年做 TeamLeader 之后开始收集的,一方面是给公司招聘用,另一方面是想用它来挖掘我在 Java 技术栈中的技术盲点,然后修复和完善它,以此来提高自己的技术水平.虽 ...

  8. java面试宝典2019(好东西先留着)

    java面试宝典2019 1.meta标签的作用是什么 2.ReenTrantLock可重入锁(和synchronized的区别)总结 3.Spring中的自动装配有哪些限制? 4.什么是可变参数? ...

  9. 【面试突击】- Java面试总则

    Java基础 1.Map.Set.List集合差别及联系详解 2.HashSet类是如何实现添加元素保证不重复的 3.HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安 ...

  10. 8年经验面试官详解 Java 面试秘诀

      作者 | 胡书敏 责编 | 刘静 出品 | CSDN(ID:CSDNnews) 本人目前在一家知名外企担任架构师,而且最近八年来,在多家外企和互联网公司担任Java技术面试官,前后累计面试了有两三 ...

随机推荐

  1. app内打开外部第三方瞎下载链接

    Q:我用cordova开发项目,想在app内跳转外部链接,安装了cordova-plugin-inappbrowser后确实可以跳转,但是跳转的页面有个按钮,原本点击会下载app,现在点击后毫无反应, ...

  2. 应用Sequelize创建项目

    创建项目: 第一步:安装express-generator -g 第二步:安装ejs模板  express --view=ejs 项目名 第三步:安装依赖进入项目 npm i ------------ ...

  3. cp 备份文件命令

    cp -p system.sh ./bak2022/systecm.sh.bak_`date '+%Y%m%d'` (备份system.sh文件后缀以bak_年月日命令)cp -rf old copy ...

  4. git reset命令适用场景详解

    ☆ git reset 场景1:本地开发环境,已提交N个commit.但尚未push,希望:①丢弃本地所有的更改,代码强制回退到某个历史版本. 解决办法:git reset --hard HEAD~回 ...

  5. 认识flutter

    flutter是谷歌的移动的ui框架,可以快速的在ios和安卓上构建高质量的原生用户界面.最主要的是完全免费开源.开发快,最重要的是使用flutter开发的开发工作者也越来越多了,生态圈也越来越好了. ...

  6. Java 数据库表关联更新

    SqlServer 关联更新语句: update a set a.pname = b.name from 表a a inner join 表b b on a.pid = b.id MySQL 关联更新 ...

  7. MacOS使用iTerm2 tab不区分大小写解答

    打开控制台 输入 vim ~/.zshrc 按下 i 之后  // i == insert插入字符 粘贴以下代码 复制到该文件中 autoload -Uz compinit && co ...

  8. CF1422

    CF1422 那个博客搭好遥遥无期. A: 看代码就行. #include<bits/stdc++.h> using namespace std; void work() { int a, ...

  9. Docker 修改容器中的mysql密码

    1.查看容器服务 docker ps2.进入mysql容器 docker exec -it mysql /bin/bash 注:mysql为容器的名字 3.登录MySQL mysql -u root ...

  10. c语言数据结构 树的基本操作

    树的基本操作有创建,插入,删除,以及各种遍历的应用,如:利用后序遍历求高度,利用前序遍历求层数的结点 基本算法思路:创建二叉树函数参数必须接受二级指针!如果使用同级指针,无法返回创建后的结果,利用递归 ...