高レイテンシ環境におけるパフォーマンスチューニングの要点
本記事では、高レイテンシ環境で Db2 for i の性能を劇的に改善するために、実践した RTT(ラウンド・トリップ・タイム)を最小化するための具体的なチューニング手法をまとめます。
オンプレミスにあったバッチサーバを AWSへ移行した際、Db2 for i(AS/400)への大量データ取得処理で、極端な性能劣化が発生しました。直接的な原因は、オンプレミスに残したDBサーバ間とのネットワーク・レイテンシ増加(約 1.3~2.1 ms → 21.1~21.3 msへ劣化)にありました。
当初、レイテンシ増加に原因があることを疑い、一般的な対策である TCPウィンドウサイズの調整や JDBCのFetch Sizeの調整を試みましたが、思うような結果とならず、なかなか解決の糸口が見つかりませんでした。最終的に、Db2 for iでは他の DBにはない block size という設定(JDBC block size)も合わせて調整しないと Fetch Size の効果が出ないこと、そして、この二つのパラメータの「整合性」がパフォーマンス改善の鍵であることがわかりました。
基本的にはラウンドトリップ発生回数をいかに少なく抑えるかが肝になりますが、そのためには以下パラメータを状況に応じて最適にチューニングする必要があります。
1. 着目すべきパラメータ
fetchSize (JDBC API)
- クライアントが「一度に欲しい行数」を指定する
Statement.setFetchSize(int rows)で設定可能- Db2 for i以外のDBでも一般的に用意されている設定。
- デフォルト:10
- 最適値導出にあたってのヒント:block size で指定するサイズ以上となるレコード数を指定する事。指定レコード数から求まるデータサイズがblock sizeに満たない場合は非効率な転送となる。
block criteria
- クライアント側からの転送要求に対しブロック単位での転送をするかどうかの設定
- 以下設定が可能
- “0” : ブロック転送をしない。実質1レコード単位の転送。
- “1”: FOR FETCH ONLY が指定されていると、ブロック転送。
- “2”: FOR UPDATE の指定がない限り、ブロック転送。
- デフォルト:2 (強制的にブロック転送)
- 最適値導出にあたってのヒント:デフォルトのままである事。
block size(JDBCブロックサイズ)
- データベースI/Oのブロックサイズとは異なる設定です。(これはDb2 for i 独自の設定)
- サーバ→クライアント転送時の「1ブロックのサイズ(KB単位で指定)」。1回のRTTで転送するデータサイズの事。
- デフォルト:32 (32KB) 最大512(512KB)の指定ができる。
- 大きくすると1回の転送で多くのデータを送れるため、RTT(往復回数)が減る。
- 設定方法:接続URLまたは接続プロパティで
block size=値 - 当パラメータが有効になるのはblock criteriaパラメータが”1″or”2″である事、prefetch=trueとなっている事が前提。
- 最適値導出にあたってのヒント:なるべく大きい値(最大512)を指定する事。
prefetch(ネットワークプリフェッチという理解でよいと思う)
- prefetchパラメータは、クライアントからのデータ転送要求に備えあらかじめblock sizeに指定されたデータを先回りして用意しておくか否かを指定するもの。
- 指定した場合(prefetch=trueの時)リード・アヘッド(先読み)が行われ転送データが準備されるようになる。
- デフォルト:true
- 設定方法:接続URLまたは接続プロパティで
prefetch=true/falseを設定する。 - 最適値導出にあたってのヒント:デフォルトのままである事。
- 等設定がtrueの時サーバ側でプリフェッチされるサイズは以下のように決まるためそれぞれ最適な値設定が求められます。
$$\text{実際にプリフェッチされるサイズ} = \text{Min} \left(
\begin{array}{l}
1.\text{Fetch Sizeで要求されたデータ総量} \\
2.\text{block sizeの設定容量} \\
3.\text{結果セットに残っているデータ総量}
\end{array}
\right)$$
lazy close
- 同一セッション内でSQLを連続実行する際、前回 Stmt のクローズ:stmt.close()で発生するRTTを省略できる。(次のStmt要求のタイミングでクローズも兼ねるため)
- デフォルト:false
- SQLの実行回数が少ない場合ほぼ恩恵がありませんが、RTTの発生回数を確実に少なくできる対策です。
2. 設定例(接続URL)
String url = "jdbc:as400://myhost;"
+ "prefetch=true;" // プリフェッチを有効化
+ "block criteria=2;" // 常にブロック転送を強制
+ "block size=512;"; // 転送単位を512KBに設定
+ "lazy close=true;"; // クローズ処理のRTTを削減
Connection conn = DriverManager.getConnection(url, "myuser", "mypassword");
PreparedStatement ps = conn.prepareStatement("SELECT * FROM customer ORDER BY sustid");
ps.setFetchSize(10000); // クライアント側ではblock sizeを意識し要求
ResultSet rs = ps.executeQuery();
参考資料 IBM Toolbox for Java JDBC driver properties
IBM i
Many properties can be specified when connecting to a server database using JDBC. All properties are optional and can be...

