次のシナリオがあります。クライアントがサーバーにファイルをアップロードしています。ファイルはHibernateを介してOracleデータベースに保存されます。最近まで、ファイルをモデル化したエンティティにはbyte[]
、Blobをモデル化するための配列属性がありました。InputStream
サーバーのRAMにファイル全体を入れたくないので、これをに変更しました。近い将来、より多くのユーザーがより大きなファイルをアップロードすることを期待しているため、RAMは確かに問題です。
私はいくつかのパフォーマンステストを行いましたが、これまでの結果は、バイト配列を挿入する場合と比較して、ストリーミングが約1.8倍遅いことを示しています。10回の反復で100MBのファイルを挿入した結果は次のとおりです。
Method Mean Duration [ms] SD [ms]
---------------------------------------
Byte Array 10733.0 264.0
Streaming 18089.0 913.0
クライアントとサーバー間の通信はSpringRMIを使用して行われ、バイナリデータ自体のストリーミングはRMIIOを使用して行われます。RMIIOを使用しているため、独自のBlobtypeを作成する必要がありました。この場合、クライアントからバイナリをアンラップして、blobのバイナリストリームにプッシュします。このためのコードは以下で見ることができます。
私がこれまでにしたこと:
- 問題がどこにあるかを絞り込むために、RMIIOストリームをサービスメソッドでラップ解除してバイト配列に入れ、データベースに保存しました。そうすることで、バイト配列をずっと使用するのと同じパフォーマンスが得られます。したがって、パフォーマンスの低下はRMIIOパッケージによるものではなく、サーバーとデータベースの間のどこかによるものです。
- バッファサイズを変更すると、パフォーマンスにわずかな影響があります
ストリームの挿入がバイト配列の挿入に比べて非常に遅い理由について、誰かが洞察を共有できますか?
私の構成:
- 春3.1.1
- RMIIO 2.0.0
- Hibernate 3.6.10
- Oracle 11.2.0.1.0
- Oracle Driver for JDBC 10.2.0.5.0
バイト配列を持つ古いエンティティ(挿入が高速です):
@Entity
@Table(name = "MYBINARYOBJECT")
public class MyBinaryObject {
@Id
private Long id;
@Lob
private byte[] bytes;
}
入力ストリームを持つ新しいエンティティ(挿入が遅い):
@Entity
@Table(name = "MYBINARYSTREAMOBJECT")
public class MyBinaryStreamObject {
@Id
private Long id;
@Type(type = "MyBlobType")
private RemoteInputStream bytes;
}
カスタムBlobタイプ:
public class MyBlobType extends AbstractLobType {
@Override
protected Object nullSafeGetInternal(ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException, IOException, HibernateException {
RemoteInputStreamServer server = new GZIPRemoteInputStream(lobHandler.getBlobAsBinaryStream(rs, names[0]));
return server.export();
}
@Override
protected void nullSafeSetInternal(PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException, IOException, HibernateException {
BufferedInputStream stream = null;
try {
((RemoteInputStream) value).available();
stream = new BufferedInputStream(
RemoteInputStreamClient.wrap((RemoteInputStream) value, RemoteRetry.NEVER), 16384);
lobCreator.setBlobAsBinaryStream(ps, index, stream, -1);
} catch (IllegalArgumentException e) {
throw new MyStreamingException();
}
}
}