Mr. Cappuccino的第28杯咖啡——金三银四面试题之Netty篇

1. 谈谈OSI七层模型?

应用层:Http协议、电子文件传输、文件服务器等
表示层:解决我们不同系统之间语法的通讯
会话层:建立与应用程序之间的通讯
传输层:提供了端口号和接口协议TPC/UDP
网络层:为数据包选择路由 路由器、交换机,定义了ip地址,可以根据ip地址找到对应的服务器
数据链路层:传输有地址的帧以及错误检测功能
物理层:以二进制形式,在物理机器上实现传输
在这里插入图片描述
在这里插入图片描述

2. TCP与UDP区别?

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议;
TCP协议应用场景:HTTP、HTTPS、FTP协议;
UDP是面向无连接通讯协议,UDP通讯时不需要接受方确定,属于不可靠传输,可能会存在丢包的现象;
UDP协议应用场景:QQ语音、QQ视频;
在这里插入图片描述

3. 谈谈TCP的三次握手和四次挥手?

三次握手:
第一次握手:客户端会向服务器端发送码为syn=1,随机产生一个seq_number=x的数据包到服务器端 (syn)
第二次握手:服务端接受到客户端请求之后,确认ack=x+1, 于是就向客户端发送syn(服务端独立生成 随机生成数字Y)+ack
第三次握手:客户端接受syn(随机数Y)+ack,向服务器端发送ack=y+1,此包发送完毕即可 建立tcp连接。

白话文翻译:
第一次握手:客户端向服务器端发送 问服务器你在不在?
第二次握手:服务器端回应客户端说:我在的。
第三次握手:客户端发送给服务器端:ok,那我开始建立连接的

四次挥手:
第一次挥手: 客户端向服务器端发送释放的报文,停止发送数据 fin=1、生成一个序列号seq=u;
第二次挥手: 服务器端接受到释放的报文后,发送ack=u+1;随机生成的seq=v给客户端;当前状态为关闭等待状态,客户端收到了服务器确认通知之后,此时客户端就会进入到终止状态,等待服务器端发送释放报文。
第三次挥手:服务器端最后数据发送完毕之后,就向客户端发送连接释放报文,FIN=1,ack=u+1 当前为半关闭状态,随机生成一个随机树w
第四次挥手,客户端必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

白话文翻译:
第一次挥手 客户端向服务端发送一个释放连接通知;
第二次挥手 服务端接受到释放通知之后,告诉给客户端说等待一下,因为可能存在有其他的数据没有发送完毕,等待数据全部传输完毕之后就开始 关闭连接;
第三次挥手 服务器端所有的数据发送完毕之后,就告诉客户端说现在可以释放连接了。
第四次挥手: 客户端确认是最终释放连接通知,ok 就开始 就向服务区端发送我们可以开始关闭连接啦;

4. BIO、NIO、AIO的区别?

BIO(Blocking IO) 同步阻塞模型:一个线程处理一个客户端请求;缺点:如果线程使用过多的情况下,非常消耗服务器端CPU的资源;应用场景:BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高。
NIO(Non Blocking IO) 同步非阻塞模型:多个客户端发送连接请求注册到(多路复用器)selector中,多路复用器使用轮训机制实现检测每个IO请求有数据就进行处理。底层实现原理:I/O多路复用底层一般用的Linux API(select,poll,epoll)来实现。应用场景:NIO方式适用于连接数目多且连接比较短(轻操作) 的架构, 比如聊天服务器, 弹幕系统, 服务器间通讯,编程比较复杂, JDK1.4 开始支持
NIO 有三大核心组件: Channel(通道), Buffer(缓冲区),Selector(选择器)
1.Channel(通道) :称之为通道,和IO相连,通信双方进行数据交流的通道,需要和buffer结合使用。
2.Buffer(缓冲区) :对数据的读取/写入需要使用buffer,buffer本质就是一个数组。
3.Selector(选择器): IO多路复用 一个线程Thread使用选择器Selector通过轮询的方式去监听多个通道Channel上的事件,从而让一个线程可以处理多个事件。
AIO(NIO 2.0) 异步非阻塞模型:由操作系统完成后回调通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用。是在NIO的基础上进一步封装的。应用场景:AIO方式适用于连接数目多且连接比较长(重操作)的架构,JDK7开始支持
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5. 谈谈IO多路复用底层的三种方式?
  1. 使用select的情况下,底层采用数组方式存放,每次调用遍历的时间复杂度为O(n),有可能会产生空轮训,比如保存1万个连接,最终只有1个连接有传输数据。监视的文件描述符被限制,由用户态切换为内核态;
  2. 使用poll底层采用链表结构存放,每次调用遍历的时间复杂度就是为O(n),Poll与select之间区别不是很大;select监视器单个进程可监视的fd数量被限制,而poll没有监视的fd数量限制;
  3. epoll采用事件通知回调方式,避免空轮休时间复杂度为o(1);由内核态切换为用户态。
    在这里插入图片描述
6. 什么是Netty?

Netty是一款基于NIO(Non blocking I/O,非阻塞IO)开发的网络通信框架,对比于BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高。

7. 为什么要使用Netty?
  1. 传统NIO的类库和API繁杂,使用麻烦:需要熟练掌握Selector、 ServerSocketChannel、 SocketChannel、ByteBuffer等。
  2. 开发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、心跳处理、半包读写、网络拥塞和异常流的处理等等。
  3. Netty对JDK自带的NIO的API进行了良好的封装,解决了上述问题。且Netty拥有高性能、吞吐量更高,延迟更低,减少资源消耗,最小化不必要的内存复制等优点。
8. Netty有什么优点?

异步非阻塞通讯;
高效的线程模型;
无锁化的设计;
高性能序列化框架;
零拷贝、内存池;
灵活的TCP协议参数设置;

9. Netty有哪些使用场景?

RPC框架Dubbo(Netty+动态代理设计模式);
RocketMQ;
聊天室;
游戏;
Xxl-job分布式任务调度平台;

10. 如何解决TCP的拆包与沾包问题?
  1. 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包;
  2. 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包;
  3. 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包;
  4. 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MSS。

MSS (最大报文段长度):
最大报文段长度(MSS)是TCP协议的一个选项,用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度(不包括文段头)。
解决方案:LineBasedFrameDecoder、Delimiterbasedframedecoder

11. 谈谈零拷贝的实现原理?

零拷贝主要的任务就是避免CPU将数据从一块存储拷贝到另外一块存储,主要就是利用各种零拷贝技术,避免让CPU做大量的数据拷贝任务,减少不必要的拷贝,或者让别的组件来做这一类简单的数据传输任务,让CPU解脱出来专注于别的任务。这样就可以让系统资源的利用更加有效。
通过MMAP+write、Sendfile实现零拷贝。
read()系统调用的过程中会把内核缓冲区的数据拷贝到用户的缓冲区里,于是为了减少这一步开销,我们可以用mmap()替换read()系统调用函数。
mmap()系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作。

Linux内核 在2.1版本:
可以直接把内核缓冲区里的数据拷贝到 socket 缓冲区里,不再拷贝到用户态,这样就只有 2 次上下文切换,和 3 次数据拷贝 但是这还不是真正的零拷贝技术
Linux内核 在2.4版本:
sendfile() 系统调用的过程发生了点变化,DMA控制器就可以直接将内核缓存中的数据拷贝到网卡的缓冲区里,此过程不需要将数据从操作系统内核缓冲区拷贝到 socket 缓冲区中,这样就减少了一次数据拷贝;这就是所谓的零拷贝(Zero-copy)技术
因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的,总体来看,零拷贝技术可以把文件传输的性能提高至少一倍以上。

在这里插入图片描述
加上直接内存DMA,减少CPU的拷贝次数。
在这里插入图片描述
在这里插入图片描述
使用mmap()代替read()
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

12. Netty可以实现哪些线程模型?

单Reactor单线程:所有操作都在同一个NIO线程处理,在这个单线程中要负责接收请求,处理IO,编解码所有操作,相当于一个饭馆只有一个人,同时负责前台和后台服务,效率低。

  1. 一个NIO线程同时处理成百上千的连接,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送。
  2. 当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,成为系统的性能瓶颈。
  3. 可靠性问题:一旦NIO线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。
    使用场景:客户端发送连接数量有限,且业务线程处理时间非常快 可以使用单个线程维护多个不同连接 ,代表有Redis。

优点:
不需要上下文切换 、不存在线程安全的问题

缺点:

  1. 只有一个线程处理,无法发挥cpu多核的效率
  2. 如果请求比较多的情况下,容易遇到瓶颈
  3. 某种意外的原因线程终止了,导致整个系统模块无法使用。
    适用于客户端连接数量有一定限制,业务处理时间非常快。
    在这里插入图片描述

单Reactor多线程:相当于一个饭馆有一个前台负责接待,有很多服务员去做后面的工作,这样效率就比单线程模型提高很多。

  1. 由一个Reactor线程-Acceptor线程用于监听服务端,接收客户端连接请求;
  2. 网络I/O操作读、写等由Reactor线程池负责处理;
  3. 一个Reactor线程可同时处理多条链路,但一条链路只能对应一个Reactor线程,这样可避免并发操作问题;
  4. 绝大多数场景下,Reactor多线程模型都可以满足性能需求,但是,在极个别特殊场景中,一个Reactor线程负责监听和处理所有的客户端连接可能会存在性能问题。例如并发百万客户端连接,或者服务端需要对客户端握手进行安全认证,但是认证本身非常损耗性能。因此,诞生了第三种线程模型;

优点:
可以充分利用多线程多核处理能力 ,处理效率比单线程要快

缺点:
对线程之间访问数据,有可能遇到线程安全问题。
在这里插入图片描述
多Reactor多线程(主从多线程模型):一组线程池接收请求,一组线程池处理IO。

  1. 服务端使用一个独立的主Reactor线程池来处理客户端连接,当服务端收到连接请求时,从主线程池中随机选择一个Reactor线程作为Acceptor线程处理连接;
  2. 链路建立成功后,将新创建的SocketChannel注册到sub reactor线程池的某个Reactor线程上,由它处理后续的I/O操作。
  3. Main Reactor负责监听server socket,用来处理新连接的建立,将建立的socketChannel指定注册给sub Reactor。
  4. Sub Reactor维护自己的selector, 基于main Reactor 注册的socketChannel多路分离IO读写事件,读写网 络数据,对业务处理的功能,另其扔给worker线程池来完成。

在这里插入图片描述

13. 谈谈Netty的线程模型?
  1. Netty核心抽象出:两个线程池bossGroup和workerGroup;
  2. bossGroup负责事件的接收,workerGroup负责处理该时间的IO流读写;
  3. NioEventLoopGroup类似于是一个事件循环组,该组有有多个不同的事件循环 NioEventLoop 表示一个不断循环的执行处理任务的线程, 每个 NioEventLoop 都有一个 Selector , 用于监听绑定在其上的 Socket 的网络通讯;
  4. new NioEventLoopGroup(BossGroup(接收线程)、WorkerGroup(工作线程)) 可以有多个线程, 即可以含有多个 NioEventLoop;
  5. BossGroup(接收线程) 负责轮训接收accept事件,并且其注册到 Worker 的 NIOEventLoop 上的 Selector,处理该队列任务;
  6. WorkerGroup(工作线程) 轮询read, write 事件 处理IO事件 在找到对应的NioScocketChannel 处理;

默认的情况下 BossGroup 和 WorkerGroup 子线程数是:当前CPU核数*2
在这里插入图片描述

14. Netty有哪些核心API?

Bootstrap:启动引导类;
ServerBootstrap:服务端启动引导类;
Future:监听IO读写;
Channel:连接通道;
Selector:IO多路复用选择器;
ChannelHandler:处理Channel通道数据;
Pipeline(ChannelPipeline):存放n个不同的ChannelHandler(采用双向链表实现,存放编码、解码、心跳检测等等);
ChannelHandlerContext:保存Channel相关的所有上下文信息;
TaskQueue:为了防止 某个Handler 中有个长时间的操作,会造成 Pipeline管道的阻塞 可以使用taskQueue提交任务异步执行;
ChannelOption:在创建Channel实例后,一般都需要设置ChannelOption参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值