2013-03-15 108 views
6

我试图从一个java程序创建300M文件,我从旧的文件API切换到新的java 7 nio包,但是新的包会去甚至比旧的还要慢。Java 7的nio.file包在创建新文件时速度很慢

我看到的CPU利用率比我在使用旧的文件API时少,但是我正在运行这个简单的代码,并且我获得了0.5Mbytes/sec的文件传输速率,而且来自java的写入正在读取一个磁盘并写入另一个(写入是访问磁盘的唯一进程)。

Files.write(FileSystems.getDefault().getPath(filePath), fiveToTenKBytes, StandardOpenOption.CREATE); 

有没有希望在这里获得合理的吞吐量?


更新:

我拆包从大文件中3亿5-10K字节的图像文件。我有3个磁盘,1个本地和2个SAN连接(大文件上的典型吞吐速率约为20MB /秒)。

我也试过这个代码,它将速度提高到几乎不到2MB/sec的吞吐量(解压这些文件需要9天的时间)。

ByteBuffer byteBuffer = ByteBuffer.wrap(imageBinary, 0, (BytesWritable)value).getLength()); 
FileOutputStream fos = new FileOutputStream(imageFile); 
fos.getChannel().write(byteBuffer); 
fos.close(); 

我从本地磁盘读取并写入SAN连接的磁盘。我从Hadoop SequenceFile格式读取数据,hadoop通常可以使用基本相同的代码以20MB /秒的速度读取这些文件。

唯一不合适的地方,除了超级慢,我看到更多的读取IO,而不是写入IO大约2:1,尽管序列文件是gziped(图像实际上是1:1的比例虽然),所以压缩文件应该是大约。 1:1与输出。


月2日更新

看着iostat我看到一些奇数,我们正在寻找xvdf在这里,我有一个java程序从xvdb读取和写入xvdf并没有ohter流程活跃xvdf

iostat -d 30 
Device:   tps kB_read/s kB_wrtn/s kB_read kB_wrtn 
xvdap1   1.37   5.60   4.13  168  124 
xvdb    14.80  620.00   0.00  18600   0 
xvdap3   0.00   0.00   0.00   0   0 
xvdf   668.50  2638.40  282.27  79152  8468 
xvdg   1052.70  3751.87  2315.47  112556  69464 

的读取xvdf是10X的写入,这是令人难以置信的。

fstab 
/dev/xvdf  /mnt/ebs1  auto defaults,noatime,nodiratime  0  0 
/dev/xvdg  /mnt/ebs2  auto defaults,noatime,nodiratime  0  0 
+0

这些文件有多大? – parsifal 2013-03-15 14:07:57

+0

@parsifal“我想创建300M文件[0123]” – Puce 2013-03-15 14:14:48

+2

我读为“我试图创建300万(或千)文件”,而不是“我试图创建一个文件,这是300 Mb的大小“(否则,为什么使用”M“而不是”Mb“?)。 – parsifal 2013-03-15 14:15:43

回答

1

我认为你的缓慢来自创建新文件,而不是实际的转移。我相信在Linux中创建一个文件是一个同步操作:系统调用将不会返回,直到文件被创建并且目录被更新。这表明你可以做几件事:

  • 使用多个写入器线程和一个读取器线程。读取器线程将从源文件读取数据到byte[],然后创建一个Runnable,从该数组写入输出文件。使用有很多线程的threadpool - 可能是100或更多 - 因为他们将花费大部分时间等待creat完成。根据您拥有的内存量设置此池入站队列的容量:如果您的文件大小为10k,那么队列容量为1,000似乎是合理的(没有理由让读者在作者之前过分靠前,所以你甚至可以使用线程数的两倍)。
  • 而不是NIO,请使用基本的BufferedInputStream s和BufferedOutputStreams。这里的问题是系统调用,而不是内存速度(NIO类旨在防止堆和堆内存之间的副本)。

我打算假设您已经知道不要试图将所有文件存储到一个目录中。甚至可以在一个目录中存储超过几百个文件。

而作为另一种选择,您是否考虑过S3进行存储?我猜测它的存储键比实际的目录效率高得多,并且有一个filesystem,它允许你像存储文件一样访问存储桶(我自己还没有尝试过)。

+0

我确实创建了2个进程,并且磁盘速度急剧下降,但2个进程的聚合速度为2MB /秒,稍微好一点,但看起来并不像更多的异步进程有助于这种情况。至于S3,这是我的第一个想法,它发生了巨大的爆炸。他们的技术人员在线上2周试图获得300M文件上传失败,并且花费我10k的使用费,即使它第一次工作(它肯定不会),你只是为了上传文件而说3k。观看那些价值$ 0.10/100的小费,它会让你快速上升! – 2013-03-17 03:13:49

+0

我现在正在尝试大文件(我可以快速创建),并在大文件中存储指向字节的指针。到目前为止,这一切都变得更加顺利,而且这是我在阅读时使用的方法。当我完成时,我会发布它的成功。 – 2013-03-17 03:15:02

+0

最终结果:不要做300M小文件。我们正在转向一个更复杂的系统,在该系统中,我们将二进制数据加载到大文件中,并保持二进制数据的索引偏移量。我们也在尝试使用大型的mysql/myisam表作为一个不错的选择。 – 2013-03-17 13:17:34

2

如果我理解正确的代码,你分割/写在一小块一小块的300M的文件(“fiveToTenKBytes”)。可以考虑使用a Stream approach

如果您正在写入磁盘,请考虑使用BufferedOutputStream封装OutputStream。

E.g.像这样:

try (BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.getPath(filePathString), StandardOpenOption.CREATE))){ 

... 

} 
+0

@JoachimSauer感谢编辑,但StackOverflow与方法链接有问题... – Puce 2013-03-15 14:13:03

+0

我知道,但我添加的链接工作正常(至少对我而言)。而现在的那个只会带你进入'Files'文档,因为它有空间。 – 2013-03-15 14:14:49

+0

啊,它似乎是在IE 8中的一个问题。在Firefox它的作品。 – Puce 2013-03-15 14:17:27