Java 性能调优实战
刘超
前金山软件技术经理
59174 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
开篇词 (1讲)
模块一 · 概述 (2讲)
结束语 (1讲)
Java 性能调优实战
15
15
1.0x
00:00/00:00
登录|注册

08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?

多路复用器(Selector)
通道(Channel)
避免阻塞,优化I/O操作
使用DirectBuffer减少内存复制
使用缓冲区优化读写流操作
阻塞
多次内存复制
Java I/O的基本类
流的概念
思考题
优化I/O操作
传统I/O的性能问题
什么是I/O
高并发下I/O瓶颈解决

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

你好,我是刘超。
提到 Java I/O,相信你一定不陌生。你可能使用 I/O 操作读写文件,也可能使用它实现 Socket 的信息传输…这些都是我们在系统中最常遇到的和 I/O 有关的操作。
我们都知道,I/O 的速度要比内存速度慢,尤其是在现在这个大数据时代背景下,I/O 的性能问题更是尤为突出,I/O 读写已经成为很多应用场景下的系统性能瓶颈,不容我们忽视。
今天,我们就来深入了解下 Java I/O 在高并发、大数据业务场景下暴露出的性能问题,从源头入手,学习优化方法。

什么是 I/O

I/O 是机器获取和交换信息的主要渠道,而流是完成 I/O 操作的主要方式。
在计算机中,流是一种信息的转换。流是有序的,因此相对于某一机器或者应用程序而言,我们通常把机器或者应用程序接收外界的信息称为输入流(InputStream),从机器或者应用程序向外输出的信息称为输出流(OutputStream),合称为输入 / 输出流(I/O Streams)。
机器间或程序间在进行信息交换或者数据交换时,总是先将对象或数据转换为某种形式的流,再通过流的传输,到达指定机器或程序后,再将流转换为对象数据。因此,流就可以被看作是一种数据的载体,通过它可以实现数据交换和传输。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了Java I/O在高并发、大数据业务场景下的性能问题,并提出了优化方法。文章首先介绍了I/O的基本概念,包括字节流和字符流的区别。然后指出了传统I/O的性能问题,包括多次内存复制和阻塞。针对这些问题,文章提出了优化方法,包括使用缓冲区优化读写流操作和使用DirectBuffer减少内存复制。通过这些优化方法,可以提升系统的整体性能,减少不必要的数据拷贝和上下文切换,从而解决高并发下的I/O瓶颈问题。文章还介绍了NIO的优化原理,包括通道(Channel)和多路复用器(Selector)的作用,以及NIO在处理大量I/O连接请求时的优势。最后,文章提出了思考题,探讨了为什么现在很多容器的通信框架仍然使用NIO而不是AIO。整体而言,本文通过深入分析和优化方法的提出,为读者提供了深入理解和解决高并发I/O性能问题的思路和方法。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 性能调优实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(57)

  • 最新
  • 精选
  • ZOU志伟
    老师,为什么要字符流还是没懂

    作者回复: 我们通常在通信时,使用的是字节流FileInputStream来实现数据的传输,你会发现,我们在读取read()和写入write()的时候都是先将字符转成字节码再进行写入操作,同样读取也是类似。如果是中文,在gbk中一般一个中文占用两个字节,如果通过字节流的方式只读取一个字节,是无法转编码为一个中文汉字。 而字符流就是为了解决这种问题,如果用字符流去读取,字符流会根据默认编码一次性的读取一个字符,即若若是gbk编码就会一次读取2个字节。因此字符流是根据字符所占字节大小而决定读取多少字节的。这就是字符流和字节流的本质不同。

    2019-06-19
    4
    73
  • Only now
    老师能不能讲讲DMA和Channel的区别, DMA需要占用总线, 那么Channel是如何跳过总线向内存传输数据的?

    作者回复: 一个设备接口试图通过总线直接向外部设备(磁盘)传送数据时,它会先向CPU发送DMA请求信号。外部设备(磁盘)通过DMA的一种专门接口电路――DMA控制器(DMAC),向CPU提出接管总线控制权的总线请求,CPU收到该信号后,在当前的总线周期结束后,会按DMA信号的优先级和提出DMA请求的先后顺序响应DMA信号。CPU对某个设备接口响应DMA请求时,会让出总线控制权。于是在DMA控制器的管理下,磁盘和存储器直接进行数据交换,而不需CPU干预。数据传送完毕后,设备接口会向CPU发送DMA结束信号,交还总线控制权。 而通道则是在DMA的基础上增加了能执行有限通道指令的I/O控制器,代替CPU管理控制外设。通道有自己的指令系统,是一个协处理器,他实质是一台能够执行有限的输入输出指令,并且有专门通讯传输的通道总线完成控制。

    2019-06-06
    3
    52
  • 张学磊
    在Linux中,AIO并未真正使用操作系统所提供的异步I/O,它仍然使用poll或epoll,并将API封装为异步I/O的样子,但是其本质仍然是同步非阻塞I/O,加上第三方产品的出现,Java网络编程明显落后,所以没有成为主流

    作者回复: 对的,异步I/O模型在Linux内核中没有实现

    2019-06-06
    50
  • 皮皮
    老师,个人觉得本期的内容讲的稍微浅了一点,关于IO的几种常见模型可以配图讲一下的,另外就是linux下的select,poll,epoll的对比应用场景。最重要的目前用的最多的IO多路复用可以深入讲一下的。

    作者回复: 你好,这篇I/O性能优化主要是普及NIO对I/O的性能优化。I/O这块的知识点很多,包括IO模型、事件处理模型以及操作系统层的事件驱动,如果都压缩到一讲,由于字数有限,很难讲完整。对于一些童鞋来说,也不好理解。 我将会在后面的一讲中,补充大家提到的一些内容。谢谢你的建议。

    2019-06-06
    28
  • 小兵
    很多知识linux 网络 I/O模型底层原理,零拷贝技术等深入讲一下,毕竟学Java性能调优的学员都是有几年工作经验的, 希望老师后面能专门针对这次io 出个补充,这一讲比较不够深入。

    作者回复: 这一讲中提到了DirectBuffer,也就是零拷贝的实现。谢谢你的建议,后面我会补充下几种网络I/O模型的底层原理。

    2019-06-07
    14
  • -W.LI-
    老师好!隔壁的李好双老师说一次普通IO需要要进过六次拷贝。 网卡->内核->临时本地内存->堆内存->临时本地内存->内核->网卡。 directbfuffer下 网卡->内核->本地内存->内核->网卡 ARP下C直接调用 文件->内核->网卡。 李老师说的对么? 本地内存和堆内存都是在用户空间的是么?

    作者回复: 李老师说的对的

    2019-06-20
    6
    13
  • td901105
    在少量连接请求的情况下,使用这种方式没有问题,响应速度也很高。但在发生大量连接请求时,就需要创建大量监听线程,这时如果线程没有数据就绪就会被挂起,然后进入阻塞状态。一旦发生线程阻塞,这些线程将会不断地抢夺 CPU 资源,从而导致大量的 CPU 上下文切换,增加系统的性能开销。 后面一句一旦发生线程阻塞,这些线程会不断的抢夺CPU资源,从而导致大量的CPU进行上下文切换,增加系统开销,这一句不是太明白,能解释一下吗?阻塞线程不是不会占用CPU资源吗?

    作者回复: 阻塞线程在阻塞状态是不会占用CPU资源的,但是会被唤醒争夺CPU资源。操作系统将CPU轮流分配给线程任务,当线程数量越多的时候,当某个线程在规定的时间片运行完之后,会被其他线程抢夺CPU资源,此时会导致上下文切换。抢夺越激烈,上下文切换就越频繁。

    2019-12-04
    3
    10
  • 课后思考及问题 1本文核心观点 1-1:JAVA IO操作为啥分为字节流和字符流?我们知道字符到字节必须经过转码,这个过程非常耗时,如果我们不知道编码类型就很容易出现乱码问题。所以 I/O 流提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。 有个疑问,字符流虽然在不知道其编码类型的情况下可以操作,不过一旦需要进行网络传输了,还是必须要知道的? 1-2:一次读取数据的操作流程,如下 用户空间—请求数据—内核空间—请求数据—数据存储设备—响应数据—内核空间—响应数据—用户空间,应用程序从用户空间的数据缓存区中读取数据,数据以字节流的形式流转。这种方式数据经过了两次复制过程,比较耗性能。 1-3:传统IO耗性能的地方主要有两点,一是数据从从存储设备到应用程序中经历了两次复制,二是数据的处理方式是阻塞式的 1-4:NIO快就快在解决了传统IO的两个耗性能的问题,一是减少复制次数,二是数据处理线程不再阻塞,为此增加了缓存区+通道+多路复用选择器+操作系统数据缓存区 对比来看,感觉老师讲的有点凌乱,IO网络通信模型,我在很多的课程上都学过,这个几乎讲到高性能这一块是必讲的,极客时间里有好几个专栏里也都有讲,大概原理还行,不过体系和细致成度一般,可能是篇幅有限吧! 我见过最通俗易懂的讲解就是netty权威指南的李林峰,用了好几章来讲解这一块的内容。 他从IO的历史演进来讲,一个个IO通信模型是怎么来的?前一个有什么问题?后一个基本是为了解决前一个的问题而来的,以及具体是怎么解决的? 磁盘或网络IO由于其内部结构决定和内存、各级缓存、CUP的速度有巨大的鸿沟,写操作系统的大神们和JDK的大神都清楚,所以,他们也都在绞尽脑汁来通过其他方式来尽量的解决这些问题。 希望他们的脑汁没没白绞,真心能明白他们绞尽脑汁后都产生了什么牛逼的方案。 非阻塞、零拷贝、多路复用选择器、Reactor、Preactor、DMA、epoll、通道这些概念有些理解啦有些还没,不过性能优化的原则没变还是那一套。

    作者回复: 总结的很好,这章后面需要再优化

    2019-09-07
    2
    10
  • 仙道
    有两个地方理解不了,请老师指点一下。 1.传统io请求数据没有的话就会挂起进入阻塞状态,既然进入了阻塞状态文中为什么还会说会继续强悍cpu。 2,传统io对文件边读边处理,NIO一次性将文件读到缓冲区,就这样的话问什么说NIO要快?我觉得单是读取的时间花费的是一样的

    作者回复: 1、阻塞会引起上下文切换,文中强调的是上下文切换; 2、如果能读到则是一样的。在没有bytebuff缓存的情况下,一旦读取数据的SO_RCVBUF满了,将会通知对端TCP协议中的窗口关闭(滑动窗口),将影响TCP发送端,这也就影响到了整个TCP通信的速度。而有了bytebuff,我们可以先将读取的数据缓存在bytebuff中,提高TCP的通信能力。

    2019-08-16
    8
  • Haies
    讲的很精炼,不过有三个问题没明白 1.图2的directbuffer是不是临时直接内存,和文中提到的DirectBuffer应该不是一回事吧。 2.Chanel有自己的处理器,这个何解? 3.传统I/O使用buffer后,是不是处理单位也变成块了,怎么可以优化阻塞的问题呢,不太明白?

    作者回复: 1、是通一个directbuffer,是一个临时堆外内存; 2、就是DMA处理器; 3、内存处理比磁盘处理的IO好很多。

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