作者:莫那·鲁道 ,来自:http://thinkinjava.cn

前言

Java 在 JDK 1.4 引入了 ByteBuffer 等 NIO 相关的类,使得 Java 程序员可以抛弃基于 Stream ,从而使用基于 Block 的方式读写文件.

另外,JDK 还引入了 IO 性能优化之王—— 零拷贝 sendFile 和 mmap。

但他们的性能究竟怎么样? 和 RandomAccessFile 比起来,快多少? 什么情况下快?到底是 FileChannel 快还是 MappedByteBuffer 快……

天啊,问题太多了。。。让我们慢慢分析。

看看善于利用IO零拷贝的MQ们

我们知道,Java世界有很多MQ:ActiveMQ,kafka,RocketMQ,QMQ(去哪儿MQ),他们是使用NIO零拷贝的大户。

然而,他们的性能却大相同,抛开其他的因素,例如网络传输方式,数据结构设计,文件存储方式,我们仅仅讨论 Broker 端对文件的读写,看看他们有什么不同。

下图是楼主查看源码总结的各个 MQ 使用的文件读写方式。

  • Kafka:record 的读写都是基于 FileChannel。index 读写基于 MMAP。

  • RocketMQ:读盘基于 MMAP,写盘默认使用 MMAP,可通过修改配置,配置成 FileChannel,原因是作者想避免 PageCache 的锁竞争,通过两层架构实现读写分离。

  • QMQ: 去哪儿 MQ,读盘使用 MMAP,写盘使用 FileChannel。

  • ActiveMQ 5.15: 读写全部都是基于 RandomAccessFile,这也是我们抛弃 ActiveMQ 的原因。

那么,到底是 MMAP 强,还是 FileChannel 强?

MMAP 众所周知,基于 OS 的 mmap 的内存映射技术,通过 MMU 映射文件,使随机读写文件和读写内存相似的速度。

那 FileChannel 呢?是零拷贝吗?很遗憾,不是。FileChannel 快,只是因为他是基于 block 的。

接下来,benchmark everything —— 徐妈.



Benchmark ?

如何 Benchmark? Benchmark 哪些?

既然是读写文件,自然就要看读写性能,这是最基本的。

但,注意,通常MQ会使用定时刷盘,防止数据丢失,MMAP 和 FileChannel 都有 force 方法,用于将 pageCache 的数据刷到硬盘上。

force 会影响性能吗? 答案是会。影响到什么程度呢? 不知道。

每次写入的数据大小会影响性能吗,毫无疑问会,但规则是什么呢?FileOutputStream 真的一无是处吗?答案是不一定。

一直以来,文件调优都是艺术,因为影响性能的因素太多,首先,SSD 的出现,已经让传统基于 B+ tree 的树形结构产生了自我疑问。

第二,每个文件系统的性能不同,Linux ext3 和 ext4 性能天壤之别(删除文件的性能差距在 20 倍左右)。而 Max OS 的 HFS+ 系统被 Linus 称之为“有史以来最垃圾的文件系统”.

幸运的是,苹果终于在 2017 年推送了 macOS High Sierra 和 iOS 10.3 系统,这个两个系统都抛弃了 HFS+,换成了性能更高的 APFS。

每个文件系统又可以设置不同的调度算法,另外,还有虚拟内存缺页中断带来的性能毛刺…….

(tips:良心的 RocketMQ 提供了 Linux IO 调优的脚本,这点做的不错 :)

跑题了。

楼主写了一个小项目,用于测试 Java MappedByteBuffer & FileChannel & RandomAccessFile & FileXXXputStream 的读写性能。大家也可以在自己的机器上跑跑看。



测试环境

CPU:intel i7 4核8线程 4.2GHz
内存:40GB DDR4
磁盘:SSD 读写 2GB/s 左右
JDK1.8
OS:Mac OS 10.13.6
虚拟内存: 未关闭,大小 9GB

测试注意点:

  1. 为了防止 PageCache 缓存的影响,每次都生成一个新的文件进行读取。

  2. 为了测试不同数据包对性能的影响,需要使用不同大小的数据包进行多次测试。

  3. force 对性能影响很大,应该单独测试。

  4. 使用 1GB 文件进行测试(小文件没有参考意义,大文件 mmap 无法映射)



纯粹读测试

1GB 文件:

测试 MappedByteBuffer & FileChannel & RandomAccessFile & FileInputStream.

从这张图里,我们看到,mmap 性能完胜,特别是在小数据量的情况下。其他的流,只有在4kb 的情况下,才开始反杀 mmap。


因此,读 4kb 以下的数据,请使用 mmap。


再放大看看 mmap 和 FileChannel 的比较:

根据上图,我们看到,在写入数据包大于 4kb 以上的情况下,FileChannel 等一众非零拷贝,基本完胜 mmap,除了那个一次读 1G 文件的 BT 测试。

因此,如果你的数据包大于 4kb,请使用 FileChannel



纯粹写测试

1GB 文件:

测试 MappedByteBuffer & FileChannel & RandomAccessFile & FileInputStream.

从上图,我们可以看出,mmap 性能还是一样的稳定。FileChannel 也不差,但是在 32 字节数据量的情况下,还差点意思。

再看缩略图:

我们看到,64字节 是 FileChannel 和 mmap 性能的分水岭,从 64字节开始,FileChannel 一路反杀,直到 BT 1GB 文件稍稍输了一丢丢。

因此,我们建议:如果你的数据包大小在 64 字节以上,请使用 FileChannel 写入。



异步 force 测试

我们知道,RocketMQ 使用异步刷盘,那么异步 force 对性能有没有影响呢?benchmark everything。我们使用异步线程,每 16kb 刷盘一次,看看性能如何。

mmap 一直落后,且性能很差,除了在2048 字节那里有一点点抖动,基本维持在4000左右,而没有 force 的情况下,则在 1500 左右。而 FileChannel 则完全不受 force 的影响。

在我的测试中,1GB 的文件,一次 force 需要 800 毫秒左右。buffer 越大,时间越多,反之则越小。

说个题外话,Kafka 一直不建议使用 force,大概也有这个原因。当然,Kafka 还有自己的多副本策略保证数据安全。

这里,我们得出结论,如果你需要经常执行 force,即使是异步的,也请一定不要使用 mmap,请使用 FileChannel。



总结

基于以上测试,我们得出一张图表:

假设,我们的系统的数据包在 1024 - 2048 左右,我们应该使用什么策略?

答:读使用 mmap,仅仅写使用 FileChannel。

再回过头看看 MQ 的实现者们,似乎只有 QMQ是这么做的。

当然,RocketMQ 也提供了 FileChannel 的写选项。但默认 mmap 写加异步刷盘,应该是 broker busy 的元凶吧。

而 Kafka,因为默认不 force,也是使用 FileChannel 进行写入的。

为什么使用 FileChannel 读呢?大概是因为消息的大小在 4kb 以上吧。这样一揣测,这些 MQ 的设计似乎都非常合理。

最后,能不用 force 就别用 force。如果要用 force ,就请使用 FileChannel。

长按二维码 ▲

订阅「架构师小秘圈」公众号

如有启发,帮我点个在看,谢谢↓

Java IO 性能优化大PK,什么场景用啥,都给你总结好啦!相关推荐

  1. java常见性能优化_十大最常见的Java性能问题

    java常见性能优化 Java性能是所有Java应用程序开发人员都关心的问题,因为快速使应用程序与使其正常运行同等重要. 史蒂文·海恩斯(Steven Haines)使用他在Java性能问题上的个人经 ...

  2. Java中性能优化的35种方法汇总

    原文地址:http://www.jb51.net/article/102831.htm 前言 对程序员们来说,代码优化是一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于 ...

  3. 44个Java代码性能优化总结

    转载自 44个Java代码性能优化总结 代码优化的最重要的作用应该是:避免未知的错误.在代码上线运行的过程中,往往会出现很多我们意想不到的错误,因为线上环境和开发环境是非常不同的,错误定位到最后往往是 ...

  4. 【Java】44个Java代码性能优化总结

    1.概述 转载:44个Java代码性能优化总结 代码优化的最重要的作用应该是:避免未知的错误.在代码上线运行的过程中,往往会出现很多我们意想不到的错误,因为线上环境和开发环境是非常不同的,错误定位到最 ...

  5. java 代码性能优化_Java代码性能优化的几个小技巧

    Java代码性能优化的几个小技巧 时间:2017-08-07     来源:华清远见JAVA学院 代码优化是程序员必须懂得一门学问,所以不管是程序员还是准程序员,养成良好的代码优化习惯都是必须要养成的 ...

  6. [译]GC专家系列5-Java应用性能优化的原则

    原文链接:http://www.cubrid.org/blog/dev-platform/the-principles-of-java-application-performance-tuning/ ...

  7. java程序性能优化(实例)

    java程序性能优化(实例) 一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: i ...

  8. Java程序性能优化——性能调优层次

    为了提升系统性能,开发人员可以从系统的各个角度和层次对系统进行优化.除了最常见的代码优化外,在软件架构上.JVM虚拟机层.数据库以及操作系统层都可以通过各种手段进行调优,从而在整体上提升系统的性能. ...

  9. Java多线程性能优化

    Java多线程性能优化 大家使用多线程无非是为了提高性能,但如果多线程使用不当,不但性能提升不明显,而且会使得资源消耗更大.下面列举一下可能会造成多线程性能问题的点: 死锁 过多串行化 过多锁竞争 切 ...

最新文章

  1. SAP RETAIL 为门店代码维护Plant Group
  2. linux系统内存执行elf的多种方式
  3. SAP物料帐下修改物料的价格
  4. MR21 VS MR22 对CKMLCP结果影响
  5. 数据结构Java06【赫夫曼树、概述、原理分析、代码实现(数据压缩、创建编码表、解码、压缩文件、解压文件)】
  6. 页面加载成功后调用_在微信小程序里实现图片预加载组件
  7. kali BEEF-XSS启动报错解决
  8. mysql 文件系统规划_Mysql的文件系统规划以及日志配置
  9. 控制流图|圈复杂度|基本复杂度
  10. 三大运营商的物联网卡如何收费
  11. java将Word文件转换为html文件
  12. C# ToolStrip 图标大小设置
  13. 如何找到电脑自带的浏览器
  14. UltraISO制作U盘系统盘安装CentOS经验分享
  15. 德鲁克谈《自我管理》——《哈佛商业评论》史上最受欢迎的文章
  16. 【BZOJ1269/1507】[AHOI2006]文本编辑器editor Splay
  17. FANUC机器人编码器相关报警代码及处理方法
  18. 计算机软件提取,伴奏提取_计算机软件及应用_IT计算机_专业资料
  19. nmn对血管作用怎样,nmn产品哪个牌子好,补充NMN可恢复血管的僵硬度!
  20. 企业应用超融合架构的设计实例及超融合应用场景分析

热门文章

  1. 枚举 ---- Codeforces Round #711 (Div. 2) D. Bananas in a Microwave[枚举暴力+思维优化]
  2. acwing1086||HDU4507数位dp[恨7不成妻]
  3. java 注解开发_Java中的注解到底是如何工作的?
  4. 2019 ICPC EC Finals C. Heretical … Möbius(中国剩余定理,序列检验)
  5. 【学习笔记】分治FFT
  6. luogu P4035 [JSOI2008]球形空间产生器(高斯消元 / 模拟退火)
  7. 【学习笔记】超简单的快速数论变换(NTT)(FFT的优化)(含全套证明)
  8. 十一届蓝桥杯java组-蓝肽子序列-动态规划
  9. iis 无法连接mysql_远程无法连接SQL2000及MySQL的原因和解决办法
  10. 在java中建个jsp文件_第一个jsp页面