FileChannle 和 MMAP 高性能分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MakeContral/article/details/85380197

前言

上一篇的博客中,我从底层上分析了BufferInputStream为什么效率会比FileInputStream来得高,这两种方式都是传统的IO,在JDK1.4 中NIO又多了两种新的IO方式:FileChannle 和 MMAP。这里着重来解释FileChannle的高性能的场景。

FileChannle

FileChannel 存在于 java.nio 包中,属于 NIO 的一种,但是注意 NIO 并不一定意味着非阻塞,这里的 FileChannel 就是阻塞的。那么这种新IO较与传统的IO有哪些优势呢?

其实这么说不够严谨,因为你必须用对了FileChannle,不然不存在优势之说。如何用对,就需要先从FileChannle的特点入手,FileChannel 采用了 ByteBuffer 这样的内存缓冲区,让我们可以非常精准的控制写盘的大小,这是普通 IO 无法实现的。

简单来说,传统的IO写数据时,先是往pagecache写入数据,不会马上刷到磁盘,而是将 pagecache 对应的位置标记为脏页,然后内核程序会定时将脏页的数据统一刷到磁盘中,但是为了安全起见,如果突然断电了pagecache中的数据就会丢失,所以这个定时的时间还不能太长,但我们希望的是,每次刷盘的尽可能在脏页比较多的情况下,不然对磁盘的写入效率太低

而 FileChannel 将ByteBuffer 中的数据也不会马上写入到磁盘中,也是先写到pagecache,但是FileChannel 可以控制写盘的大小,它当然会尽可能写满一块数据块,然后再调用 force() 方法,用于通知操作系统进行及时的刷盘。

所以要想提高FileChannle的效率,必须要了解当前磁盘的数据库大小然后做出写盘大小的调整,这样效率才会快,从这方面也可以看出来FileChannle在读效率上并没有什么优势。

MMAP

关于内存映射,我在前面几篇的博客中已经对其做出了详细的解释,不明白的可以先看一下。

Linux shm和mmap
内存映射 mmap的理解(转载+整理)
RocketMQ 源码分析 消息存储(预备知识二)(转载+整理)

既然已经将了这么多关于内存映射,这里为什么还要再浪费口舌继续解释呢?主要是希望对NIO的方式有一个更加系统的认识。相信大家在网上经常能看到这么一段话来描述MMAP:普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write。 当时我是不能理解的,凭什么像访问内存一样速度就快呢?

要知道访问内存就意味着可以使用指针地址来访问了,虽然在Java中没有指针这种说法。那使用地址为什么速度就快了呢?比如你要读取一个文件开头的偏移1000个字节,传统的做法是不是一个for循环遍历到1000个字节,但是现在有了指针,你就可以直接指定position就可以访问了。如果每条实际的消息规定占用10个字节,那么访问的时候,就可以直接使用 文件的起始地址 + n*10 来访问第n条消息了,这也太方便了吧!!

mmap的读:

// 读
byte[] data = new byte[4];
int position = 8;
//从当前 mmap 指针的位置读取 4b 的数据
mappedByteBuffer.get(data)//指定 position 读取 4b 的数据
MappedByteBuffer subBuffer = mappedByteBuffer.slice();
subBuffer.position(position);
subBuffer.get(data);

看到这是我在想,在RMQ中commitlog的偏移量存储在了Consume Queue中,这样是不是就可以利用上面访问内存的特性,根据偏移量快速定位到一条消息呢?只是我的猜测,如果有错,希望有大神能纠正。

同样的也可以指定position进行读写,mmap的读写:

// 写
byte[] data = new byte[4];
int position = 8;
//从当前 mmap 指针的位置写入 4b 的数据
mappedByteBuffer.put(data);
//指定 position 写入 4b 的数据
MappedByteBuffer subBuffer = mappedByteBuffer.slice();
subBuffer.position(position);
subBuffer.put(data);

参考文章

文件IO操作的一些最佳实践

猜你喜欢

转载自blog.csdn.net/MakeContral/article/details/85380197