阿里面试真题:NIO为什么不适合文件上传场景、如何优雅解决

简介: 阿里面试真题:NIO为什么不适合文件上传场景、如何优雅解决

该系列已分别介绍了服务端、客户端的启动流程,本文将重点剖析Netty是如何封装NIO的读事件。


温馨提示:本文虽然是源码分析,但强烈建议精读,根据源码阐述其背后的设计哲学,也用黑体进行了标注,请特别留意。


在阅读本篇文章之前,请稍微思考如下几个问题:


  • NIO为什么不适合文件上传等场景
  • NIO如何避免一个超大数据传送的连接对其他请求的影响
  • NIO如何处理半关闭


1、读事件概述


关于Read事件在SocketChannel与ServerSocketChannel所对应的操作不一样,在SocketChannel中,则对应数据读,而在ServerSocketChannel中则被被封装成接受客户端的连接请求。


NIO read事件入口在NioEventLoop的processSelectedKey方法,截图如下:

91f094b75b05bcc6bbea834aea8d64ee.png

其核心入口为UnSafe的read方法,关于UnSafe的类层次结构如下图所示:

60ea8be57e786cb2f0166d71385060f5.png

  • AbstractNioByteChannel的内部类NioByteUnsafe#read
    SocketChannel对应的读事件处理流程,即IO读的处理实现。
  • AbstractNioMessageChannel的内部类NioMessageUnsafe#read
    ServerSocketChannle对应的读事件处理流程。


接下来将分别介绍这两个流程。


2、IO读事件处理流程


IO读事件由AbstractNioByteChannel内部类AbstractNioUnsafe的read方法实现,接下来重点剖析该方法,从中窥探Netty对IO读事件的处理。

a0b739a09e878588b325279bc58cd073.png

Step1:如果没有开启自动注册读事件,在每一次读时间处理过后会取消读事件,默认为自动注册。


温馨提示:如果通道不注册读事件,将无法从通道中读取数据,即无法处理请求或接受响应。


如果没有开启自动读事件,需要应用程序在需要的时候手动调用通道的read方法。


取消读事件,Netty基于NIO给出了非常标准的实现,基本可以当场模板代码使用:

6859d487477f8d9bdf14f8e2a77380e3.png

其实现关键点:首先判断键值对是否有效,然后通过位运算进行取消注册。

e37b9aa2f82773a3ab711dcf6a6b6e3d.png

Step2:创建接受缓存区内存分配器,这里有两个关键点:


  • maxMessagesPerRead
    每一个通道在一次读事件处理过程中最多可以调用底层Socket进行读取的次数,默认为16次,这里的设计哲学是避免一个通道需要读取太多的数据,从而影响其他通道的数据读,因为在一个事件选择器中多个通道的读事件是串行执行的
  • RecvByteBufAllocator
    接受缓冲区的内存分配策略,分为分配固定大小(不够时扩容)、动态变化(根据历史分配的大小,动态条件合适的内存大小),这里主要的设计哲学是合理利用内存,并减少扩容,提高内存的分配效率与使用效率

cacc674916a8d38067cb1267f221451d.png

Step3:循环处理读事件,最多处理maxMessagePerRead。接下来探讨一下单次读事件的处理流程。

0b006f5cb82fbc72487fb167f4336831.png

Step4:进行一次IO读处理,其处理有如下几个关键点:


  • 首先分配一个ByteBuf,俗称接收缓存区,用来存放从网络中读取的内容。
  • 获取一下分配到的累积缓存区可写的字节数,这个后面有妙用
    调用底层网络读API从网卡中读取数据,NIO的读取实现如下所示:
    c8d488df9a8e2c0c9ad85987fabc83e4.png
  • 即调用NIO中的SocketChannel进行读数据,其返回参数表示这次从网卡中读取到的字节数。如果读取到的字节少于0,则表示对端通道已关闭,己端也需要进行相应的处理,例如关闭通道


  • 读到一批数据后,会通过事件传播机制向事件链中传播channelRead事件,触发后续对该批数据的处理。

01be729875851854dce8ef801d739b9f.png

Step5:判断该通道是否需要继续读,其基本依据如下:


  • 如果未开启自动注册读事件,读完一次之后将不再继续读取。
  • 如果本次读取到的字节数小于接收缓存区,说明此刻网卡中没有可读数据,等下一次读事件触发再继续读。

198499dc63041fc9d9441a980bfa9b34.png

Step6:一次或多次读操作结束后,会触发一次读完成事件,向整个事件链传播。


整个网络读处理流程就介绍到这了。


3、接受连接处理流程

在Netty中,服务端接收客户端的连接请求(OP_ACCEPT),被封装在channelRead 事件中,其代码入口为:AbstractNioMessageChannel 的内部类NioMessageUnsafe的read方法。

c9e7e2d9a32a4ec2c5e7f7ae3c11732e.png

其大概的实现要点在前面已经介绍,这里主要看一下NioServerSocketChannel的doReadMessage。

079d684ff402b33c75fdf5b62e93fad1.png

通过使用底层的NIO接受一个连接,并获取NioSocketChannel对象。然后继续该对象向下传播channelRead事件,在后续的处理器中对该对象进行操作,例如将其注册读事件,从而触发网络的读操作,关于NioSocketChannel如何绑定读事件、注册业务相关的事件监听器机制已经在Netty进阶:手把手教你如何编写一个NIO服务端中详细介绍,本文就不再重复。

相关文章
|
2月前
|
存储 关系型数据库 MySQL
阿里面试:为什么要索引?什么是MySQL索引?底层结构是什么?
尼恩是一位资深架构师,他在自己的读者交流群中分享了关于MySQL索引的重要知识点。索引是帮助MySQL高效获取数据的数据结构,主要作用包括显著提升查询速度、降低磁盘I/O次数、优化排序与分组操作以及提升复杂查询的性能。MySQL支持多种索引类型,如主键索引、唯一索引、普通索引、全文索引和空间数据索引。索引的底层数据结构主要是B+树,它能够有效支持范围查询和顺序遍历,同时保持高效的插入、删除和查找性能。尼恩还强调了索引的优缺点,并提供了多个面试题及其解答,帮助读者在面试中脱颖而出。相关资料可在公众号【技术自由圈】获取。
|
13天前
|
存储 NoSQL 架构师
阿里面试:聊聊 CAP 定理?哪些中间件是AP?为什么?
本文深入探讨了分布式系统中的“不可能三角”——CAP定理,即一致性(C)、可用性(A)和分区容错性(P)三者无法兼得。通过实例分析了不同场景下如何权衡CAP,并介绍了几种典型分布式中间件的CAP策略,强调了理解CAP定理对于架构设计的重要性。
46 4
|
24天前
|
消息中间件 监控 Java
BIO、NIO、AIO在不同场景下的应用对比
BIO(阻塞I/O)、NIO(非阻塞I/O)和AIO(异步I/O)是Java中处理I/O操作的三种模式。BIO适用于连接数少且稳定的场景;NIO通过非阻塞模式提高并发处理能力,适合高并发场景;AIO则完全异步,适合需要高效、低延迟的I/O操作场景。
77 4
|
1月前
|
存储 NoSQL 算法
阿里面试:亿级 redis 排行榜,如何设计?
本文由40岁老架构师尼恩撰写,针对近期读者在一线互联网企业面试中遇到的高频面试题进行系统化梳理,如使用ZSET排序统计、亿级用户排行榜设计等。文章详细介绍了Redis的四大统计(基数统计、二值统计、排序统计、聚合统计)原理和应用场景,重点讲解了Redis有序集合(Sorted Set)的使用方法和命令,以及如何设计社交点赞系统和游戏玩家排行榜。此外,还探讨了超高并发下Redis热key分治原理、亿级用户排行榜的范围分片设计、Redis Cluster集群持久化方式等内容。文章最后提供了大量面试真题和解决方案,帮助读者提升技术实力,顺利通过面试。
|
1月前
|
SQL 关系型数据库 MySQL
阿里面试:1000万级大表, 如何 加索引?
45岁老架构师尼恩在其读者交流群中分享了如何在生产环境中给大表加索引的方法。文章详细介绍了两种索引构建方式:在线模式(Online DDL)和离线模式(Offline DDL),并深入探讨了 MySQL 5.6.7 之前的“影子策略”和 pt-online-schema-change 方案,以及 MySQL 5.6.7 之后的内部 Online DDL 特性。通过这些方法,可以有效地减少 DDL 操作对业务的影响,确保数据的一致性和完整性。尼恩还提供了大量面试题和解决方案,帮助读者在面试中充分展示技术实力。
|
5月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
7月前
|
存储 监控 Java
深入探索Java语言的NIO(New I/O)技术
深入探索Java语言的NIO(New I/O)技术
|
5月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
|
5月前
|
Java 大数据
如何在Java中进行网络编程:Socket与NIO
如何在Java中进行网络编程:Socket与NIO
|
5月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
下一篇
DataWorks