1. Netty是什么?

Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护性的高性能协议服务器和客户端,Netty是基于NIO的,它封装了JDK的NIO,让我们使用起来更加方便灵活。

2. Netty的特点是什么?

  • 高并发:Netty是一款基于NIO开发的网络通信框架,对比于BIO,它的并发性能得到了很大提高。
  • 传输快:Netty的传输依赖于零拷贝特性,尽量减少不必要的内存拷贝,实现了更高效率的传输。
  • 封装好:Netty封装了NIO操作的很多细节,提供了易于使用的接口。

3. Netty有哪些优势?

  • 使用简单:封装了NIO的很多细节,使用更加简单;
  • 功能强大:预置了多种编解码功能,支持多种主流协议;
  • 定制能力强:可以通过ChannelHandler对通信框架进行灵活地扩展;
  • 性能高:通过与其他业界主流的NIO框架对比,Netty的综合性能最优;
  • 稳定:Netty修复了已经发现的所有NIO的bug,让开发人员可以专注于业务本身;
  • 社区活跃:Netty是活跃的开源项目,版本迭代周期短,bug修复速度快。

4. Netty的应用场景有哪些?

  • 互联网行业:阿里分布式服务框架:Dubbo,默认使用Netty作为基础通信组件,还有RocketMQ也是使用Netty作为通讯的基础。
  • 游戏行业:Netty作为高性能的基础通信组件,它本身提供了TCP/UDP和HTTP协议栈,非常方便定制和开发私有协议栈,账号登录服务器,地图服务器之间可以方便的通过Netty进行高性能的通信;
  • 大数据领域:Hadoop的高性能通信和序列化组件Avro的RPC框架默认采用Netty进行跨界点通信。

5. Netty高性能表现在哪些方面?

  • IO线程模型:同步非阻塞,用最少的资源做更多的事情;
  • 内存零拷贝:尽量减少不必要的内存拷贝,实现了更高效率的传输;
  • 内存池设计:申请的内存可以重用,主要指直接内存,内部实现是用一棵二叉查找树管理内存分配情况;
  • 串行化处理读写:避免使用锁带来的性能开销;
  • 高性能序列化协议:支持protobuf等高性能序列化协议;

6. BIO、NIO和AIO的区别?

  • BIO:一个连接一个线程,客户端有连接请求时服务器端就需要开启一个线程进行处理,线程开销大;
  • 伪异步IO:将请求连接放入线程池,一对多;
  • NIO:一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理;
  • AIO:一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理;
  • BIO是面向流的,NIO是面向缓冲区的,BIO的各种流是阻塞的,而NIO是非阻塞的,BIO的Stream是单向的,而NIO的channel是双向的;
  • NIO的特点:事件驱动模型,单线程处理多任务,非阻塞I/O,I/O读写不再阻塞,而是返回0,基于块的传输比基于流的传输更高效,零拷贝技术、多路IO复用大大提高了Java网络应用的可伸缩性和实用性,基于Reactor线程模型。

在Reactor模式中,事件分发器等待某个事件或某个操作的发生,事件分发器就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作,如在Reactor中实现读:注册读就绪事件和相应的事件处理器->事件分发器等待事件->事件到来->激活分发器->分发器调用事件对应的处理器->事件处理器完成实际的读操作->处理读到的数据->注册新的事件->然后返还控制权。

7. NIO的组成?

  • Buffer:与channel进行交互,数据从channel读入缓冲区,从缓冲区写入channel中;
  • clear方法:使缓冲区为一系列新的通道读取或相对放置操作做好准备,它将限制设置为容量大小,将当前位置设置为0;
  • flip方法:使缓冲区为一系列新的通道写入或相对获取操作做好准备,它将限制设置为当前位置,然后将当前位置设置为0;
  • rewind方法:重读此缓冲区,将position设置为0;
  • DirectByteBuffer:可减少一次系统空间到用户空间的拷贝,但Buffer创建和销毁的成本更高,不可控,通常会用内存池来提高性能,直接缓冲区主要分配给那些一首基础系统的本机I/O操作影响的大型、持久的缓冲区,如果数据量比较小的中小应用,可以考虑使用heapBuffer,由JVM进行管理;
  • Channel:表示IO源与目标打开的连接,是双向的,但不能直接访问数据,只能与Buffer进行交互;
  • Selector:可使一个单独的线程管理多个Channel,open方法可创建Selector,register方法向多路复用器注册通道,可以监听的事件类型:读、写、连接、accept。注册事件后会产生一个SelectionKey:它表示SelectableChannel和Selector之间的注册关系,wakeup方法:使尚未返回的第一个选择操作立即返回。

    8. Netty的线程模型?

    Netty的线程模型是基于Reactor模型的。

    Netty单线程模型

    Reactor单线程模型,是指所有的I/O操作都在同一个NIO线程上完成,此时NIO线程的职责包括:接收新连接请求,读写操作等。
    在这里插入图片描述
    在一些小容量应用场景下,可以使用单线程模型,但是对于高负载、高并发的应用场景却不合适,主要原因是:
  • 一个NIO线程同时处理成百上千的连接,性能上无法支撑,即使NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送;
  • 当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,成为系统的性能瓶颈;
  • 可靠性问题:一旦NIO线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。

Reactor多线程模型

Reactor多线程模型与单线程模型最大的区别就是有一组NIO线程来处理连接读写操作,一个NIO线程处理Accept,一个NIO线程可以处理多个连接事件,一个连接事件只能属于一个NIO线程。
在这里插入图片描述
在绝大多数场景下,Reactor多线程模型可以满足性能要求,但是在个别特殊场景下,一个NIO线程负责监听和处理所有的客户端连接可能会存在性能问题。例如并发百万客户端连接,或者服务端需要对客户端握手进行安全认证,但是认证本身非常损耗性能,在这类场景下,单独一个Acceptor线程可能会存在性能不足的问题,为了解决性能问题,产生了第三种Reactor线程模型–主从Reactor多线程模型。

Reactor主从多线程模型

主从Reactor线程模型的特点是:服务端用于接收客户端连接的不再是一个单独的NIO线程,而是一个独立的NIO线程池,Acceptor接收到客户端TCP连接请求并处理完成后(可能包含接入认证等),将新创建的SocketChannel注册到I/O线程池的某个I/O线程上,由它负责SocketChannel的读写和编解码工作,Acceptor线程池仅仅用于客户端的登录,握手和安全认证,一旦链路建立成功,就将链路注册到后端subReactor线程池的I/O线程上,由I/O线程负责后续的I/O操作。
在这里插入图片描述

9. TCP粘包/拆包的原因及解决方法?

原因:

应用程序写入的字节大小大于套接字发送缓冲区的大小,会发生拆包现象,而应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包现象;

解决办法:

  • 消息定长
  • 包尾增加特殊字符分割

10. 什么是Netty的零拷贝?

Netty的“零拷贝”主要体现在三个方面:

  • Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行socket读写,不需要进行字节缓冲区的二次拷贝,如果使用传统的堆内存(HEAP BUFFERS)进行socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中,相对于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝;
  • 第二种“零拷贝”的实现是CompositeByteBuf,它对外将多个ByteBuf封装成一个ByteBuf,对外提供统一封装后的ByteBuf接口;
  • 第三种“零拷贝”就是文件传输,Netty文件传输类DefaultFileRegion通过transferTo方法将文件发送到目标Channel中,很多操作系统直接将文件缓冲区的内容发送到目标Channel中,而不需要通过循环拷贝的方式,这是一种更加高效的传输方式,提升了传输性能,降低了CPU和内存占用,实现了文件传输的“零拷贝”。

11. Netty中有哪几种重要组件?

  • Channel:Netty网络操作抽象类,它除了包括基本的I/O操作,如bind、connect、read、write等;
  • EventLoop:主要是配合Channel处理I/O操作,用来处理连接的生命周期中所发生的事情;
  • ChannelFuture:Netty框架中所有的I/O操作都是异步的,因此我们需要ChannelFuture的addListener()注册一个ChannelFutureListener监听事件,当操作执行成功或者失败时,监听就会自动触发返回结果;
  • ChannelHandler:充当了所有处理入站和出站数据的逻辑容器,ChannelHandler主要用来处理各种事件,比如:连接,数据接收,异常,数据转换等;
  • ChannelPipeline:为ChannelHandler链提供了容器,当channel创建时,就会被自动分配到它专属的ChannelPipeline,这个关联是永久性的。

12. Netty发送消息有几种方式?

Netty有两种发送消息的方式:

  • 直接写入Channel中,消息从ChannelPipeline当中尾部开始移动;
  • 写入和ChannelHandler绑定的ChannelHandlerContext中,消息从ChannelPipeline中的下一个ChannelHandler中移动。

13. 默认情况Netty 开启多少线程,何时启动?

Netty默认是CPU处理器数的两倍,bind完之后启动。

14. 了解哪几种序列化协议?

序列化(编码)是将对象序列化为二进制形式(字节数组),主要用于网络传输,数据持久化等,而反序列化(解码)则是将从网络,磁盘等读取的字节数组还原成原始对象,主要用于网络传输对象的解码,以便完成远程调用。

影响序列化性能的关键因素:序列化后的码流大小(网络带宽的占用)、序列化的性能(CPU资源占用)、是否支持跨语言(异构系统的对接和开发语言切换)。

Java默认提供的序列化:无法跨语言、序列化后的码流台打、序列化的性能差。

XML

优点:人机可读性好,可指定元素或特性的名称;
缺点:序列化数据只包含数据本身以及类的结构,不包括类型标识和程序集信息;只能序列化公共属性和字段;不能序列化方法,文件庞大,文件格式复杂,传输占带宽;
适用场景:当作配置文件存储数据,实时数据转换。

JSON

一种轻量级的数据交换格式。
优点:兼容性高,数据格式比较简单,易于读写,序列化后数据较小,可扩展性好,兼容性好,与XML相比,其协议比较简单,解析速度比较快;
缺点:数据的描述性比XML差,不适合性能要求为ms级别的情况,额外空间开销比较大;
适用场景:跨防火墙访问、基于Web browser的Ajax请求,传输数据量相对小,实时性要求相对低的服务;

Fastjson

采用一种“假定有序快速匹配”的算法。
优点:接口简单易用,目前Java语言中最快的Json库;
缺点:过于注重快,而偏离了“标准”及功能性,代码质量不高,文档不全;
适用场景:协议交互,Web输出,Android客户端

Protobuf

将数据结构以.proto文件进行描述,通过代码生成工具可以生成对应数据结构的POJO对象和Protobuf相关的方法和属性。
优点:序列化后码流小,性能高,结构化数据存储格式(XML、JSON等),通过标识字段的顺序,可以实现协议的前后兼容,结构化的文档更容易管理和维护。
缺点:需要依赖与工具生成代码,支持的语言相对较少,官方只支持Java,C++,python;
适用场景:对性能要求高的RPC调用,具有良好的跨防火墙的访问属性,适用应用层对象的持久化。

15. Netty支持哪些心跳类型设置

  • readerIdleTime:为读超时时间
  • writerIdleTime:为写超时时间
  • allIdleTime:所有类型的超时时间

16. Netty和Tomcat的区别

  • 作用不同:Tomcat是Servlet容器,可以视为Web服务器,而Netty是异步事件驱动的网络应用程序框架和工具用于简化网络编程,例如:TCP和UDP套接字服务器。
  • 协议不同:Tomcat是基于http协议的Web服务器,而Netty能通过编程自定义各种协议,因为Netty本身能编码/解码字节流,所以Netty可以实现HTTP服务器,FTP服务器,UDP服务器,RPC服务器,WebSocket服务器,Redis的Proxy服务器,MySQL的Proxy服务器等。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

Spring Cloud面试题汇总 Previous
Redis面试题汇总 Next