面试宝典到手,搞定面试,不再是难题,系列文章传送地址,请点击本链接。

目录

1、Netty是什么?和Tomcat有什么区别?特点是什么?

2、Netty高性能体现在哪些方面?

3、Netty 有哪些应用场景?

4、Netty 核心组件有哪些?分别有什么作用?

5、EventloopGroup 了解么?和 EventLoop 啥关系?

6、Bootstrap 和 ServerBootstrap 了解么?

7、NioEventLoopGroup 默认的构造函数会起多少线程?

8、Netty 服务端和客户端的启动过程了解么?

9、Netty的线程模型是怎样的?

10、Netty的多路复用通讯方式

11、什么是 TCP 粘包/拆包?有什么解决办法呢?

12、Netty的长连接、心跳机制了解吗?

13、什么是网络滑动窗口?

14、Netty 的零拷贝了解么?

15、Netty的无锁设计和线程绑定

16、BIO、NIO和AIO的区别?


1Netty是什么?和Tomcat有什么区别?特点是什么?

Netty是一个基于NIO的异步网络通信框架,提供了TCP/UDP和文件传输的支持,性能高,封装了原生NIO编码的复杂度,开发者可以直接使用Netty来开发高效率的各种网络服务器,并且编码简单。

Tomcat是一个web服务器,是一个Servlet容器,基本上Tomcat内部只能运行Servlet程序,并处理HTTP请求,而Netty封装的是底层IO模型,关注的是网络数据的传输,而不关心具体的协议,可定制性更高。

Netty的特点:

1、异步、NIO的网络通信框架

2、高性能

3、高扩展,高定制性

4、易用性

2Netty高性能体现在哪些方面?

1、NIO模型,用最小的资源做更多的事情。

2、内存零拷贝,尽量减少不必要的内存拷贝,实现更高效的传输。(零拷贝)

3、内存池设计,申请的内存可以重用,只要指直接内存。内部实现是用一颗二叉树查找管理内存分配情况。

4、串行化处理读写:避免使用锁带来的性能开销。即消息的处理尽可能在同一个线程内完成,期间不进行线程的切换,这样就避免了多线程竞争和同步锁。表面上看,串行化设计似乎CPU利用率不搞,并发程度不够。但是,通过调整NIO线程池的线程参数,可以同时启动多个串行化的线程并行运行,这样局部无锁化的串行程序设计相比一个队里多个工作线程模型性能更优秀。

5、高性能序列化协议:支持protobuf等高性能序列化协议

6、高效并发编程的体现:volatile的大量、正确使用;CAS和原子类的广泛使用;线程安全容器的使用;通过读写锁提升并发性能。

3Netty 有哪些应用场景?

Netty 主要用来做网络通信 :

作为 RPC 框架的网络通信工具 :我们在分布式系统中,不同服务节点之间经常需要相互调用,这个时候就需要 RPC 框架了。不同服务节点之间的通信是如何做的呢?可以使用 Netty 来做。比如我调用另外一个节点的方法的话,至少是要让对方知道我调用的是哪个类中的哪个方法以及相关参数吧!实现一个自己的 HTTP 服务器 :通过 Netty 我们可以自己实现一个简单的 HTTP 服务器,这个大家应该不陌生。说到 HTTP 服务器的话,作为 Java 后端开发,我们一般使用 Tomcat 比较多。一个最基本的 HTTP 服务器可要以处理常见的 HTTP Method 的请求,比如 POST 请求、GET 请求等等。

实现一个即时通讯系统 :使用 Netty 我们可以实现一个可以聊天类似微信的即时通讯系统,这方面的开源项目还蛮多的,可以自行去 Github 找一找。

实现消息推送系统 :市面上有很多消息推送系统都是基于 Netty 来做的。......

4Netty 核心组件有哪些?分别有什么作用?

Netty核心组件包括:channel、

1.Channel

Channel 接口是 Netty 对网络操作抽象类,它除了包括基本的 I/O 操作,如 bind()、connect()、read()、write() 等。

比较常用的Channel接口实现类是NioServerSocketChannel(服务端)和NioSocketChannel(客户端),这两个 Channel 可以和 BIO 编程模型中的ServerSocket以及Socket两个概念对应上。Netty 的 Channel 接口所提供的 API,大大地降低了直接使用 Socket 类的复杂性。

2.EventLoop

“EventLoop 定义了 Netty 的核心抽象,用于处理连接的生命周期中所发生的事件”,是不是很难理解?说白了,EventLoop 的主要作用实际就是负责监听网络事件并调用事件处理器进行相关 I/O 操作的处理。

Channel 为 Netty 网络操作(读写等操作)抽象类,EventLoop 负责处理注册到其上的Channel 处理 I/O 操作,两者配合参与 I/O 操作。

3.ChannelFuture

Netty 是异步非阻塞的,所有的 I/O 操作都为异步的。因此,我们不能立刻得到操作是否执行成功,但是,你可以通过 ChannelFuture 接口的 addListener() 方法注册一个 ChannelFutureListener,当操作执行成功或者失败时,监听就会自动触发返回结果。并且,你还可以通过ChannelFuture 的 channel() 方法获取关联的Channel。

public interface ChannelFuture extends Future<Void> {

Channel channel();

ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> var1); ......

ChannelFuture sync();

throws InterruptedException;

}

另外,我们还可以通过 ChannelFuture 接口的 sync()方法让异步的操作变成同步的。

4.ChannelHandler ChannelPipeline

ChannelHandler 是消息的具体处理器。他负责处理读写操作、客户端连接等事情。

ChannelPipeline 为 ChannelHandler 的链,提供了一个容器并定义了用于沿着链传播入站和出站事件流的 API 。当 Channel 被创建时,它会被自动地分配到它专属的 ChannelPipeline。

我们可以在 ChannelPipeline 上通过 addLast() 方法添加一个或者多个ChannelHandler ,因为一个数据或者事件可能会被多个 Handler 处理。当一个 ChannelHandler 处理完之后就将数据交给下一个 ChannelHandler 。

5EventloopGroup 了解么? EventLoop 啥关系?

EventLoopGroup 包含多个 EventLoop(每一个 EventLoop 通常内部包含一个线程), EventLoop 的主要作用实际就是负责监听网络事件并调用事件处理器进行相关 I/O 操作的处理。

并且 EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理,即 Thread 和 EventLoop 属于 1 : 1 的关系,从而保证线程安全。

上图是一个服务端对 EventLoopGroup 使用的大致模块图,其中 Boss EventloopGroup 用于接收连接,Worker EventloopGroup 用于具体的处理(消息的读写以及其他逻辑处理)。

从上图可以看出:当客户端通过 connect 方法连接服务端时,bossGroup 处理客户端连接请求。当客户端处理完成后,会将这个连接提交给 workerGroup 来处理,然后 workerGroup 负责处理其 IO 相关操作。

6Bootstrap ServerBootstrap 了解么?

Bootstrap 是客户端的启动引导类/辅助类,具体使用方法如下:

EventLoopGroup group = new NioEventLoopGroup();

try {

//创建客户端启动引导/辅助类:

Bootstrap Bootstrap b = new Bootstrap();

//指定线程模型

b.group(group). ......

// 尝试建立连接

ChannelFuture f = b.connect(host, port).sync();

f.channel().closeFuture().sync();

} finally {

// 优雅关闭相关线程组资源

group.shutdownGracefully();

}

ServerBootstrap 客户端的启动引导类/辅助类,具体使用方法如下:

// 1.bossGroup 用于接收连接,workerGroup 用于具体的处理

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

EventLoopGroup workerGroup = new NioEventLoopGroup();

try {

//2.创建服务端启动引导/辅助类:

ServerBootstrap ServerBootstrap b = new ServerBootstrap();

//3.给引导类配置两大线程组,确定了线程模型 b.group(bossGroup, workerGroup).

......

// 6.绑定端口 ChannelFuture f = b.bind(port).sync();

// 等待连接关闭 f.channel().closeFuture().sync();

} finally {

//7.优雅关闭相关线程组资源

bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }

从上面的示例中,我们可以看出:

Bootstrap 通常使用 connet() 方法连接到远程的主机和端口,作为一个 Netty TCP 协议通信中的客户端。另外,Bootstrap 也可以通过 bind() 方法绑定本地的一个端口,作为 UDP 协议通信中的一端。ServerBootstrap通常使用 bind() 方法绑定本地的端口上,然后等待客户端的连接。Bootstrap 只需要配置一个线程组— EventLoopGroup ,而 ServerBootstrap需要配置两个线程组—EventLoopGroup ,一个用于接收连接,一个用于具体的处理。

7NioEventLoopGroup 默认的构造函数会起多少线程?

默认的构造函数会启动CPU核心数*2个线程。我们可以从下面内容分析得出:

回顾我们在上面写的服务器端的代码:

// 1.bossGroup 用于接收连接,workerGroup 用于具体的处理

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

EventLoopGroup workerGroup = new NioEventLoopGroup();

为了搞清楚NioEventLoopGroup 默认的构造函数 到底创建了多少个线程,我们来看一下它的源码。

/** * 无参构造函数。 * nThreads:0 */

public NioEventLoopGroup() { //调用下一个构造方法 this(0); } /** * Executor:null */ public NioEventLoopGroup(int nThreads) {

//继续调用下一个构造方法

this(nThreads, (Executor) null);

}

//中间省略部分构造函数 /** * RejectedExecutionHandler():RejectedExecutionHandlers.reject() */

public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,final SelectStrategyFactory selectStrategyFactory)

{

//开始调用父类的构造函数

super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());

}

一直向下走下去的话,你会发现在 MultithreadEventLoopGroup 类中有相关的指定线程数的代码,如下:

// 从1,系统属性,CPU核心数*2 这三个值中取出一个最大的 //可以得出 DEFAULT_EVENT_LOOP_THREADS 的值为CPU核心数*2 private static final int DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

// 被调用的父类构造函数,NioEventLoopGroup 默认的构造函数会起多少线程的秘密所在 // 当指定的线程数nThreads为0时,使用默认的线程数DEFAULT_EVENT_LOOP_THREADS protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {

super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);

}

8Netty 服务端和客户端的启动过程了解么?

请查看入门教程中的启动流程:netty服务器和客户端的启动过程

9Netty的线程模型是怎样的?

Netty同时支持Reactor单线程模型、Reactor多线程模型和Reactor主从线程模型,用户可根据启动参数配置在这三种模式中切换。

服务算启动时,通常会创建两个NioEventLoopGroup实例,对应了两个独立的Reactor线程池,bossGroup负责处理客户端的连接请求,workerGroup负责处理I/O相关操作,执行系统Task、定时任务等。用户可根据服务端引导类ServerBootStrap配置参数选择Reactor线程模型,进而最大限度满足用户的定制化需求。

10Netty的多路复用通讯方式

Netty 的 IO 线程 NioEventLoop 由于聚合了多路复用器 Selector,可以同时并发处理成百上千个
客户端 Channel,由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于
频繁 IO 阻塞导致的线程挂起。

服务端:

客户端:

11、什么是 TCP 粘包/拆包?有什么解决办法呢?

粘包

  • 现象,发送 abc def,接收 abcdef
  • 原因
  • 应用层:接收方 ByteBuf 设置太大(Netty 默认 1024)
  • 滑动窗口:假设发送方 256 bytes 表示一个完整报文,但由于接收方处理不及时且窗口大小足够大,这 256 bytes 字节就会缓冲在接收方的滑动窗口中,当滑动窗口中缓冲了多个报文就会粘包
  • Nagle 算法:会造成粘包

/拆包

  • 现象,发送 abcdef,接收 abc def
  • 原因
  • 应用层:接收方 ByteBuf 小于实际发送数据量
  • 滑动窗口:假设接收方的窗口只剩了 128 bytes,发送方的报文大小是 256 bytes,这时放不下了,只能先发送前 128 bytes,等待 ack 后才能发送剩余部分,这就造成了半包
  • MSS 限制:当发送的数据超过 MSS 限制后,会将数据切分发送,就会造成半包

本质是因为 TCP 是流式协议,消息无边界

解决思路:

  1. 短链接,发一个包建立一次连接,这样连接建立到连接断开之间就是消息的边界,缺点效率太低
  1. 每一条消息采用固定长度,缺点浪费空间
  1. 每一条消息采用分隔符,例如 \n,缺点需要转义
  1. 每一条消息分为 head 和 body,head 中包含 body 的长度

解决方法:

a、使用 Netty 自带的解码器

FixedLengthFrameDecoder: 固定长度解码器,它能够按照指定的长度对消息进行相应的拆包。

DelimiterBasedFrameDecoder : 可以自定义分隔符解码器,

LineBasedFrameDecoder 实际上是一种特殊的 DelimiterBasedFrameDecoder 解码器。发送端发送数据包的时候,每个数据包之间以换行符作为分隔,LineBasedFrameDecoder 的工作原理是它依次遍历 ByteBuf 中的可读字节,判断是否有换行符,然后进行相应的截取。LengthFieldBasedFrameDecoder:预设长度解码器

b、自定义解码器

除了上面的自带解码器之外,如果还有特殊需求,我们可以自定义解码器。

12Netty的长连接、心跳机制了解吗?

Netty的长短连接:

TCP 在进行读写之前,server 与 client 之间必须提前建立一个连接。建立连接的过程,需要我们常说的三次握手,释放/关闭连接的话需要四次挥手。这个过程是比较消耗网络资源并且有时间延迟的。

短连接说的就是 server 端 与 client 端建立连接之后,读写完成之后就关闭掉连接,如果下一次再要互相发送消息,就要重新连接。短连接的有点很明显,就是管理和实现都比较简单,缺点也很明显,每一次的读写都要建立连接必然会带来大量网络资源的消耗,并且连接的建立也需要耗费时间。

长连接说的就是 client 向 server 双方建立连接之后,即使 client 与 server 完成一次读写,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。长连接的可以省去较多的 TCP 建立和关闭的操作,降低对网络资源的依赖,节约时间。对于频繁请求资源的客户来说,非常适用长连接。

心跳机制:

在 TCP 保持长连接的过程中,可能会出现断网等网络异常出现,异常发生的时候, client 与 server 之间如果没有交互的话,它们是无法发现对方已经掉线的。为了解决这个问题, 就需要引入 心跳机制

心跳机制的工作原理是: 在 client 与 server 之间在一定时间内没有数据交互时, 即处于 idle 状态时, 客户端或服务器就会发送一个特殊的数据包给对方, 当接收方收到这个数据报文后, 也立即发送一个特殊的数据报文, 回应发送方, 此即一个 PING-PONG 交互。所以, 当某一端收到心跳消息后, 就知道了对方仍然在线, 这就确保 TCP 连接的有效性.

TCP 实际上自带的就有长连接选项,本身是也有心跳包机制,也就是 TCP 的选项:SO_KEEPALIVE。但是,TCP 协议层面的长连接灵活性不够。所以,一般情况下我们都是在应用层协议上实现自定义心跳机制的,也就是在 Netty 层面通过编码实现。通过 Netty 实现心跳机制的话,核心类是 IdleStateHandler 。

13、什么是网络滑动窗口?

  • TCP 以一个段(segment)为单位,每发送一个段就需要进行一次确认应答(ack)处理,但如果这么做,缺点是包的往返时间越长性能就越差

  • 为了解决此问题,引入了窗口概念,窗口大小即决定了无需等待应答而可以继续发送的数据最大值

  • 窗口实际就起到一个缓冲区的作用,同时也能起到流量控制的作用
  • 图中深色的部分即要发送的数据,高亮的部分即窗口
  • 窗口内的数据才允许被发送,当应答未到达前,窗口必须停止滑动
  • 如果 1001~2000 这个段的数据 ack 回来了,窗口就可以向前滑动
  • 接收方也会维护一个窗口,只有落在窗口内的数据才能允许接收

14Netty 的零拷贝了解么?

维基百科是这样介绍零拷贝的:

“零复制(英语:Zero-copy;也译零拷贝)技术是指计算机执行操作时,CPU 不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省 CPU 周期和内存带宽。

在 OS 层面上的 Zero-copy 通常指避免在 用户态(User-space) 与 内核态(Kernel-space) 之间来回拷贝数据。而在 Netty 层面 ,零拷贝主要体现在对于数据操作的优化。

1、使用 Netty 提供的 CompositeByteBuf 类, 可以将多个ByteBuf 合并为一个逻辑上的 ByteBuf, 避免了各个 ByteBuf 之间的拷贝。

2、ByteBuf 支持 slice 操作, 因此可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf, 避免了内存的拷贝。

3、通过 FileRegion 包装的FileChannel.tranferTo 实现文件传输, 可以直接将文件缓冲区的数据发送到目标 Channel, 避免了传统通过循环 write 方式导致的内存拷贝问题.

15Netty的无锁设计和线程绑定

Netty 采用了串行无锁化设计,在 IO 线程内部进行串行操作,避免多线程竞争导致的性能下降。表面上看,串行化设计似乎 CPU 利用率不高,并发程度不够。但是,通过调整 NIO 线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列多个工作线程模型性能更优。

Netty 的 NioEventLoop 读取到消息之后,直接调用 ChannelPipeline 的fireChannelRead(Object msg),只要用户不主动切换线程,一直会由 NioEventLoop 调用到用户的 Handler,期间不进行线程切换,这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看是最优的。

16BIONIOAIO的区别?

详细见:https://blog.csdn.net/wanghaiping1993/article/details/124907695

面试宝典在手,搞定大厂面试,不再是难题,系列文章传送地址,请点击本链接。https://blog.csdn.net/wanghaiping1993/article/details/125075785

netty面试题及答案相关推荐

  1. Netty面试题和答案

    Netty面试题和答案 1.BIO. NIO 和 AIO 的区别? BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理.线 程开销大. 伪异步 IO:将请求连接放入线程池, ...

  2. 100道 Dubbo面试题及答案(2021最新)

    Redis面试题及答案[2021最新版]Dubbo面试题大全(2021版),发现网上很多Dubbo面试题都没有答案,所以花了很长时间搜集,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小 ...

  3. Java 最常见的 10000+ 面试题及答案整理:持续更新

    Java面试题以及答案整理[最新版]Java高级面试题大全(2021版),发现网上很多Java面试题都没有答案,所以花了很长时间搜集,本套Java面试题大全,汇总了大量经典的Java程序员面试题以及答 ...

  4. redis常见面试题有哪些?redis集群面试题及答案整理

    下面要给大家带来的是一整套的redis集群面试题,包含了具体的面试题目和答案,想要来看这方面面试题的小伙伴可以来了解一下. 一.面试题及答案 1.Redis有哪些适合的场景? (1)Session共享 ...

  5. 整理阿里巴巴社招最新面试题及答案,附复学习笔记,面试成功归来

    前言 这是我大概回忆整理的Java面试题,里面有很多知识点,主要还是在于Java基础,当然数据结构跟算法最好也要懂,是加分项,如果不会,果断说,否则,面试官深入问,问到你愣住了,这样浪费了自己的面试题 ...

  6. 115道Java面试题及答案分享,java程序员赶紧收好

    115道Java经典面试题(面中率最高.最全) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可 ...

  7. 2020年5月面试精心整理java面试题,覆盖了大部分面试题(附答案)

    今年的工作格外难找,不知道别的小伙伴什么样子,反正我是不好找,由于疫情影响,每个公司都在缩减成本,要求也变高了.很多公司要求第一学历统招本科,虽然是本科,但不是统招,很难混啊.面了一个多月,初试复试面 ...

  8. 2020年拼多多校招面试题及答案-最全最新-持续更新中(2)

    大家好我是好好学习天天编程的天天 一个整天在互联网上种菜和砍柴的程序员~ 2020年拼多多校招面试题及答案-最全最新-持续更新中(2) 2020年拼多多校招面试题一面 2020年拼多多校招面试题一面- ...

  9. Java最新面试题及答案

    2022最新Java面试题及答案参考.喜欢的朋友点个赞吧.欢迎收藏.评论区留言.顶贴! 文章目录 某大型银行1面 某大型金融机构1面 某大型银行2-3面 某大型手机厂商1-2面 某大型银行1面 1.你 ...

  10. 「高级java工程师」常见面试题及其答案(持续更新)

    「java工程师」常见面试题及其答案请见: 「java工程师」常见面试题及其答案(持续更新)_好人老李的博客-CSDN博客 目录 java基础 常用的 jvm 调优方法? OOM的常见场景及其原因.解 ...

最新文章

  1. csv文件简介(转载)
  2. Ubuntu13.10下编译安装opencv2.4.9
  3. 从零点五开始用Unity做半个2D战棋小游戏(六)
  4. 最长连续序列Python解法
  5. oem监控mysql_OEM12c 安装配置MySQL Plug-in用来监控MySQL
  6. MYSQL模式匹配:REGEXP和like用法
  7. CH372或CH375的USB通讯问题解答
  8. 服务器安装找不到lsi驱动,IBM 服务器 SAS Raid LSI Windows2008 硬盘 驱动
  9. 办公室计算机打印机共享,办公室共享连接打印机全攻略,办公人必会操作技能...
  10. 超好的 MARKINGCODE查询网 电子元件丝印
  11. Android(小米miui)如何判断当前应用是否允许NFC权限
  12. viewpager 与 pageradapter
  13. 孟岩大大《理解矩阵一二三》语录
  14. Chinaren校友录所用的左边弹出式菜单
  15. Corrective feedback
  16. wang editor Vue使用 + 使用自己方法上传图片
  17. 计算机设置共享时出现无法保存,如何解决win7提示无法保存打印机设置(错误0x000006d9)...
  18. python图像处理(图像缩放)
  19. html摄像头图片抓取,html5 – 从网络摄像头捕获图像
  20. POJ 1379 Run Away 模拟退火

热门文章

  1. 总和生育率模型matlab,中国人口增长预测 灰色模型——全国数学建模大赛
  2. 移动网站建设应注意哪些问题?
  3. 实现手风琴抽屉式网页特效
  4. 斗地主系列之牌型大小比较
  5. 软件的静态测试和动态测试【软件测试分类】
  6. linux ansys内存不够,ANSYS 硬件配置建议
  7. APP瘦身之资源优化篇
  8. Windows自带便签工具Sticky Notes
  9. 《MarkDown编辑器的使用技巧(修改录入方式与目录生成)|CSDN编辑器测评》
  10. 通过搜狗搜索爬取微信公众号文章,小程序版可体验