6

Javaプログラムから3億個のファイルを作成しようとしていますが、古いファイルAPIから新しいjava 7 nioパッケージに切り替えましたが、新しいパッケージは古いパッケージよりもさらに遅くなります。

古いファイルAPIを使用していたときよりもCPU使用率が低くなっていますが、この単純なコードを実行していると、0.5Mバイト/秒のファイル転送速度が得られ、Javaからの書き込みは1つのディスクを読み取り、別の(書き込みはディスクにアクセスする唯一のプロセスです)。

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

ここで妥当なスループットを得る希望はありますか?


アップデート:

大きなファイルから3億の5-10kバイトの画像ファイルを解凍しています。私は3つのディスクを持っており、1つはローカルで2つはSANが接続されています(すべて、大きなファイルで最大20MB /秒のスループットレートがあります)。

また、速度を2MB /秒未満のスループット(これらのファイルを解凍するのに9日)に改善するこのコードを試しました。

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

ローカルディスクから読み取り、SANに接続されたディスクに書き込みます。私はHadoopSequenceFile形式から読み取っていますが、hadoopは通常、基本的に同じコードを使用して20MB/秒でこれらのファイルを読み取ることができます。

非常に遅いことを除いて、場違いに見える唯一のことは、シーケンスファイルがgzipされているにもかかわらず、書き込みIOよりも読み取りIOが約2:1多いことです(ただし、画像は実質的に1:1の比率になります)。圧縮ファイルは約である必要があります。出力と1:1。


2回目の更新

iostatいくつかの奇数が表示されています。ここではxvdfが表示されています。読み取りと書き込みを行うJavaプロセスが1つありxvdbxvdf他のプロセスはアクティブではありません。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は書き込みの10倍であり、信じられないほどです。

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

2 に答える 2

2

私があなたのコードを正しく理解していれば、あなたは300Mのファイルを小さなチャンク( " fiveToTenKBytes")に分割/書き込みしています。

ストリームアプローチの使用を検討してください。

ディスクに書き込む場合は、OutputStreamをBufferedOutputStreamでラップすることを検討してください。

例:

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

 ...

}
于 2013-03-15T14:00:23.037 に答える
1

あなたの遅さは、実際の転送ではなく、新しいファイルの作成に起因していると思います。Linuxでは、ファイルの作成は同期操作であると思います。ファイルが作成され、ディレクトリが更新されるまで、システムコールは返されません。これは、あなたができることがいくつかあることを示唆しています。

  • 単一のリーダースレッドで複数のライタースレッドを使用します。リーダースレッドは、ソースファイルからにデータを読み取り、この配列から出力ファイルを書き込むbyte[]を作成します。多くのスレッド(おそらく100以上)を含むスレッドプールを使用します。これは、スレッドが完了するのを待つためにほとんどの時間を費やすためRunnableです。使用しているメモリの量に基づいて、このプールのインバウンドキューの容量を設定します。ファイルのサイズが10kの場合、キューの容量は1,000が妥当と思われます(リーダーがライターよりもはるかに先を行くことを許可する正当な理由はありません)。 、したがって、スレッド数の2倍の容量で実行することもできます)。creat
  • NIOではなく、基本的なBufferedInputStreamsとを使用しBufferedOutputStreamsます。ここでの問題は、メモリ速度ではなく、システムコールです(NIOクラスは、ヒープメモリとオフヒープメモリ間のコピーを防ぐように設計されています)。

すべてのファイルを単一のディレクトリに保存しようとしないことをすでに知っていると思います。または、1つのディレクトリに数百を超えるファイルを保存することもできます。

また、別の方法として、ストレージにS3を検討しましたか?バケットキーは実際のディレクトリよりもはるかに効率的であり、ファイルであるかのようにバケットにアクセスできるファイルシステムがあると思います(自分で試したことはありません)。

于 2013-03-16T18:54:39.877 に答える