消息队列高手课
李玥
美团高级技术专家
52199 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 42 讲
进阶篇 (21讲)
消息队列高手课
15
15
1.0x
00:00/00:00
登录|注册

11 | 如何实现高性能的异步网络传输?

解决多路复用的核心问题
提供Selector对象解决一个线程在多个网络连接上的多路复用问题
使用EventLoopGroup对象执行数据收发的业务逻辑
自动处理线程控制、缓存管理、连接管理等问题
提供了友好的API设计
需要实现收到数据后的处理逻辑
需要少量线程处理大量连接
适合使用异步设计提升系统性能
大部分时间执行IO操作,包括网络IO、磁盘IO和外围设备访问
解决IO等待问题
异步模型不会阻塞线程,等资源准备好后再通知业务代码处理
NIO
Netty框架
理想的异步网络框架
IO密集型系统
异步与同步模型
如何实现高性能的异步网络传输?

该思维导图由 AI 生成,仅供参考

你好,我是李玥。上一节课我们学习了异步的线程模型,异步与同步模型最大的区别是,同步模型会阻塞线程等待资源,而异步模型不会阻塞线程,它是等资源准备好后,再通知业务代码来完成后续的资源处理逻辑。这种异步设计的方法,可以很好地解决 IO 等待的问题。
我们开发的绝大多数业务系统,都是 IO 密集型系统。跟 IO 密集型系统相对的另一种系统叫计算密集型系统。通过这两种系统的名字,估计你也能大概猜出来 IO 密集型系统是什么意思。
IO 密集型系统大部分时间都在执行 IO 操作,这个 IO 操作主要包括网络 IO 和磁盘 IO,以及与计算机连接的一些外围设备的访问。与之相对的计算密集型系统,大部分时间都是在使用 CPU 执行计算操作。我们开发的业务系统,很少有非常耗时的计算,更多的是网络收发数据,读写磁盘和数据库这些 IO 操作。这样的系统基本上都是 IO 密集型系统,特别适合使用异步的设计来提升系统性能。
应用程序最常使用的 IO 资源,主要包括磁盘 IO 和网络 IO。由于现在的 SSD 的速度越来越快,对于本地磁盘的读写,异步的意义越来越小。所以,使用异步设计的方法来提升 IO 性能,我们更加需要关注的问题是,如何来实现高性能的异步网络传输。
今天,咱们就来聊一聊这个话题。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

异步网络传输在IO密集型系统中具有重要意义。本文介绍了异步网络传输的重要性以及如何实现高性能的异步网络传输。文章首先介绍了IO密集型系统和计算密集型系统的区别,强调了异步设计在解决IO等待问题上的优势。接着讨论了理想的异步网络框架应该具备的特点,强调了需要少量线程处理大量连接,并且能够及时处理数据的到来。随后,文章介绍了使用Netty框架来实现异步网络通信的方法,重点强调了Netty提供的友好API和自动处理复杂问题的优势。最后,文章简要介绍了使用NIO来实现异步网络通信的方法,强调了Selector对象的作用和解决多路复用问题的重要性。 传统的同步网络IO难以支持高并发和高吞吐量,因此异步网络IO框架成为解决方案。Netty和NIO是两种常见的异步网络框架,它们在API设计方面有所差异。Netty自动解决了线程控制、缓存管理和连接管理等问题,用户只需实现对应的Handler来处理数据。而NIO提供了Selector机制,用单个线程管理多个连接,解决了多路复用问题。 针对接收数据这一流程,Netty是如何用NIO来实现的呢?这是一个值得深入探讨的问题。 总的来说,本文通过介绍异步网络传输的重要性和两种实现方法,为读者提供了深入了解异步网络传输的基础知识和实践方法。异步网络传输对于IO密集型系统的重要性不言而喻,而选择合适的异步网络框架也是至关重要的。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《消息队列高手课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(48)

  • 最新
  • 精选
  • 游弋云端
    关于JAVA的网络,之前有个比喻形式的总结,分享给大家: 例子:有一个养鸡的农场,里面养着来自各个农户(Thread)的鸡(Socket),每家农户都在农场中建立了自己的鸡舍(SocketChannel) 1、BIO:Block IO,每个农户盯着自己的鸡舍,一旦有鸡下蛋,就去做捡蛋处理; 2、NIO:No-Block IO-单Selector,农户们花钱请了一个饲养员(Selector),并告诉饲养员(register)如果哪家的鸡有任何情况(下蛋)均要向这家农户报告(select keys); 3、NIO:No-Block IO-多Selector,当农场中的鸡舍逐渐增多时,一个饲养员巡视(轮询)一次所需时间就会不断地加长,这样农户知道自己家的鸡有下蛋的情况就会发生较大的延迟。怎么解决呢?没错,多请几个饲养员(多Selector),每个饲养员分配管理鸡舍,这样就可以减轻一个饲养员的工作量,同时农户们可以更快的知晓自己家的鸡是否下蛋了; 4、Epoll模式:如果采用Epoll方式,农场问题应该如何改进呢?其实就是饲养员不需要再巡视鸡舍,而是听到哪间鸡舍的鸡打鸣了(活跃连接),就知道哪家农户的鸡下蛋了; 5、AIO:Asynchronous I/O, 鸡下蛋后,以前的NIO方式要求饲养员通知农户去取蛋,AIO模式出现以后,事情变得更加简单了,取蛋工作由饲养员自己负责,然后取完后,直接通知农户来拿即可,而不需要农户自己到鸡舍去取蛋。

    作者回复: 这个比喻非常赞👍

    2019-08-15
    8
    291
  • 课后思考及建议 没有对比就没有伤害,尤其对于学习,对比一下就知道那个课程优秀,那个更优秀。 首先,我觉得如何实现高性能的网络通信,是必须要讲的,这个原理是脱离具体语言的,和什么实现框架也没什么关系。 不过篇幅有限老师只能讲解一下她的精髓,如果想一点点弄明白,建议看看李林峰大哥的《netty权威指南(第二版)》她用了三章来讲解网络通信模型的演进。 另外,我同时在学kafka的专栏,我发现一个现象,两位老师都没有先将一个消息的全生命历程先细致的讲一下,学习过丁奇老师的MySQL,他上来就讲解了一下一个SQL语句是怎么执行的。我觉得很有整体感,知道整个过程之后其实下面再细致的讲解都是性能优化的事情啦! 我猜想其他各种系统,尤其是和数据打交道的都类似,只要一个完整的流程知道了,下面好多知识都是在为这个系统的性能、健壮性、高可用性、自身的其他特性在加强。 所以,我提过这样的问题,也建议先讲一下一条消息从发送到接收都经历了那些关键环节或组件,对一条消息的全生命历程有个整体的认识。然后再讲每个关键环节为什么这么实现,其性能最佳吞吐量最高。然后再讲各个组件是怎么紧密配合的,如果我知道一个软件是什么?又清楚他由什么组成?每一部分为什么如此设计?那些设计是通用的那些设计比较独特?我觉得我就理解了这个软件 老师的课程非常优秀,哈哈,我觉得听了我的建议还可以再优秀一点点

    作者回复: 感谢你的建议!

    2019-08-23
    6
    62
  • 业余草
    多回到队列上来吧。Netty几乎很多Java课都会讲到。。。

    作者回复: 我们还是需要一个例子能让大家理解异步网络传输的。

    2019-08-15
    5
    24
  • 喜欢地球的阿培同学
    老师您好,我上周问了你2个问题。 分别在第17讲和第11讲 第一个问题: 一个是100个线程,1个线程在运行,99个线程在阻塞(等待锁释放),会不会造成线程频繁上下文切换。你回答的是不会。 第二个问题: 我又问了一个 Selector.select()方法是一个阻塞方法,这个线程会一直卡在这儿。你的回答我理解过后是会造成线程上下文切换 那为什么第一个问题不会造成线程上下文频繁切换呢? 是因为底层操作系统的原因吗? 而普通的socket连接阻塞,是会造成线程上下文切换?

    作者回复: 方法在阻塞时,你要区分它的线程状态,如果是你说的等待锁,那线程的状态是waiting,是不会申请cpu时间片的,那就不会上下文切换。 如果是这个方法呢: void blockMethod() { while(....) {doSomeThing();} } 对于这个调用者看来,也是阻塞在这个调用这个blockMethod方法上了,但是线程是RUNNING状态,这个时候肯定是要申请CPU时间片的。 Selector.select()在阻塞时,它的内部实现根据操作系统和epoll的配置不同,实际上有好几种实现,不同的实现行为也不一样。

    2020-04-20
    14
  • 喜欢地球的阿培同学
    最后文中有一段话: "Selecor 通过一种类似于事件的机制来解决这个问题。首先你需要把你的连接,也就是 Channel 绑定到 Selector 上,然后你可以在接收数据的线程来调用 Selector.select() 方法来等待数据到来。这个 select 方法是一个阻塞方法,这个线程会一直卡在这儿,直到这些 Channel 中的任意一个有数据到来,就会结束等待返回数据。" 这个 select 方法是一个阻塞方法,这个线程会一直卡在这儿,岂不是和上篇文章的同步转账类似,该线程会处于等待状态,无法充分利用cpu资源。

    作者回复: Selector本身是阻塞的,但它只需要阻塞一个线程,就可以等待多个socket连接,任何一个连接有数据进来就会解除阻塞。这就是所谓的“多路复用”。

    2020-04-16
    2
    9
  • 青禾qingh
    老师,nio不是异步的吧,我理解是同步非阻塞的,当然非阻塞也仅仅是指读写数据的时候,select也是阻塞的,我理解aio才是异步的

    作者回复: 严格来说,是这样的。

    2020-05-11
    4
    6
  • 川杰
    老师,以下是我的理解:异步网络框架中,通过线程池处理接收消息的情况,和同步相比,好处在于,同步框架下,一个连接必须有两个线程(等数据的线程、处理数据的线程),当连接过多时会有大量频繁的上下文切换;而异步框架利用线程池接管了(等数据的线程)的作用,减少了上下文切换、线程的创建销毁的开销; 问题是:虽然线程池完成了数据接收的功能,但加入消息发送方发来了大量的消息,因为线程池的线程数量毕竟是有限的,此时是否就会出现消息不能及时转发给数据处理线程的情况呢?

    作者回复: 你说的这个问题是有可能出现的。

    2019-08-15
    2
    4
  • leslie
    Java基础太差:几乎不懂;故而其实本课程学习让我觉得越多Java相关的非常吃力,希望老师后面的课程里面纯Java的东西能浅一点或者告知Java的理解大概要什么水平。 刘超老师的趣谈linux在跟着学、张磊的深入剖析Kubernetes目前学了一遍。我想从用这种方式去理解或解释不知道原理是否类似正确吧:希望老师提点或者下堂课时解答。 其实Netty基于NIO就像Kubernetes其实是基于Cgroup和Namespace一样:其实Netty是使用了NIO的Selecor去处理线程的异步机制,Netty在它的基础上去优化了其线程控制和连接管理并追加了缓存管理,请老师指正;谢谢。 努力跟着学习,努力跟着做题;希望完课的时候能从另外一个高度/层次去理解和使用消息队列。

    作者回复: 放心,我们这门课使用的任何语言都不会特别深入,更多的是讲实现原理,语言只是讲解和举例的载体。

    2019-08-15
    4
  • humor
    老师,就算是SSD,随机查询的速度也会非常慢吧,那为什么SSD就不用考虑异步呢?

    作者回复: 是的,SSD同样是,顺序读写远远比随机读写快。 至于异步的方式并不适合用来读写磁盘,读数据的时候肯定要等待磁盘返回数据,写入的时候,虽然可以用异步写来大幅提升响应时间,但其实牺牲了数据可靠性。

    2020-05-17
    3
  • 杰哥长得帅
    同步的时候,每个连接都需要阻塞一个线程来等待数据,大量的连接数就会需要相同数量的数据接收线程。当这些 TCP 连接都在进行数据收发的时候,会导致什么情况呢?对,会有大量的线程来抢占 CPU 时间,造成频繁的 CPU 上下文切换,导致 CPU 的负载升高,整个系统的性能就会比较慢。 老师能详细解释下 “大量线程用于数据接收时,为什么又会有大量线程来抢占cpu时间” 吗

    作者回复: 因为接收数据这些操作都需要cpu来执行。接收数据的这个操作,实际上就是把数据从socket 缓冲区复制到用户程序的内存空间,然后执行用户代码去解析数据等其他业务逻辑,这些操作都需要CPU来执行。

    2019-09-02
    2
收起评论
显示
设置
留言
48
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部