web-dev-qa-db-ja.com

spring / hibernateの読み取り専用データベーストランザクションの実行速度が読み書きより遅いのはなぜですか?

私は、読み取り専用データベースと読み取り/書き込みデータベースのトランザクションのパフォーマンスに関する調査を行ってきました。 MySQLサーバーは低速のVPNリンクを介してリモートにあるため、トランザクションタイプの違いを簡単に確認できます。これは、1番目と2番目のJDBC呼び出しの比較に基づいて動作していることがわかっている接続プーリングを使用したものです。

DAO呼び出しで読み取り専用トランザクションを使用するようにSpring AOPを構成すると、呼び出しは読み取り/書き込みと比較して30-40%slowerです。

<!-- slower -->
<tx:method name="find*" read-only="true" propagation="REQUIRED" />
...
// slower
@Transaction(readOnly = true)

対:

<!-- faster -->
<tx:method name="find*" read-only="false" propagation="REQUIRED" />
...
// faster
@Transaction

Tcpdumpを見ると、読み取り専用トランザクションがMySQLとやり取りしているようです。 読み取り専用ダンプ読み取り-書き込み です。

  1. 読み取り専用呼び出しに時間がかかっている理由を誰でも説明できますか。これは予想されますか?

  2. ネットワークの改善以外に速度を改善するために私が間違っていることやできることはありますか? 良好なパフォーマンスの推奨事項 でこの素晴らしい投稿を見つけました。他にコメントはありますか?

どうもありがとう。

28
Gray

Spring/hibernateの読み取り専用データベーストランザクションの実行速度が読み書きより遅いのはなぜですか?

わかりました。これは興味深いライドでした。私が学び、共有することがたくさんあります。以下のいくつかは明白なはずでしたが、うまくいけば私の無知と私が学んだことは他の人に役立つでしょう。

<tldr>質問#1に対する短い答えは、休止状態が_set session.transaction.read.only_同期JDBC呼び出しで@Transaction(readOnly = true)セッションを開始し、_set session.transaction.read.write_呼び出しで終了することでした。これらの呼び出しは、読み取り/書き込み呼び出しを行うときに送信されないため、読み取り専用呼び出しが遅くなりました。 </ tldr>

質問2に対するより長い回答には、リモートデータベースのパフォーマンスを低下させようとするために行った手順の次の詳細が含まれます。

  1. 最初にしたことは、データベースVPNをTCP=からUDPに切り替えてから OpenVPN最適化ページ でした。ため息。これについて知っていたはずです。 OpenVPNクライアントとサーバー設定の設定に従うと、読み取り専用トランザクションのオーバーヘッドは480ミリ秒から141ミリ秒に低下しましたが、読み取り/書き込みの100ミリ秒を超えていました。

    _; Got these from: https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux
    proto udp
    tun-mtu 6000
    fragment 0
    mssfix 0
    _
  2. Tcpdumpの出力(_tcpdump ... -X_が勝利の場合)をよく見ると、不要な自動コミットと読み取り専用/読み取り/書き込みJDBC呼び出しが多数行われていることに気付きました。素晴らしい HikariCP接続プール ライブラリの新しいバージョンにアップグレードすると、これが役立ちました。バージョン2.4.1では、これらの呼び出しの一部を削減するインテリジェンスが追加されました。 120msまでの読み取り専用トランザクションのオーバーヘッド。まだ100ミリ秒で読み書きします。いいね.

  3. HikariCPの作者であるBrett Wooldridgeが、MySQLドライバーの設定が役立つかもしれないと指摘しました。どうもありがとう。 MySQL JDBC URLに次の設定を追加すると、ドライバーは接続のソフトウェア状態を使用し、サーバーにステータスを要求しません。

    _jdbc:mysql://.../database?useLocalSessionState=true&useLocalTransactionState=true
    _

    これらの設定により、より多くの同期JDBCコマンドが削除されました。読み取り専用トランザクションのオーバーヘッドは60ミリ秒に低下し、現在は読み取り/書き込みと同じです。うわー.

    編集/警告:ドライバーがトランザクション情報を送信していないバグが見つかった後、実際に_useLocalTransactionState=true_を追加してロールバックしました。

  4. しかし、tcpdumpの出力をさらに調べてみると、読み取り専用/読み取り/書き込みトランザクション設定が送信されているのを見ました。私の最後の修正は、接続への最初の呼び出しがconnection.setReadOnly(true)である場合、特別なプールから接続を提供するカスタム読み取り専用検出プールを作成することでした。

    このカスタムプールを使用すると、読み取り専用接続と読み取り/書き込み接続の両方のトランザクションオーバーヘッドが20ミリ秒に低下しました。基本的に、JDBCトランザクションのオーバーヘッド呼び出しの最後を削除したと思います。これが 私が書いた2つのクラス のソースです。コードは比較的もろく、Hibernateが最初にconnection.setReadOnly(true)を実行することに依存していますが、うまく機能しているようで、XMLとコードで注意深く文書化しました。

したがって、基本的な_@Transaction_オーバーヘッドは、数日間の作業で480msから20msになりました。 dao.find(...)メソッドの100回の「実際の」休止状態呼び出しは、55秒で開始され、4.5秒で終了しました。かなりお尻を蹴る。常に10倍の速度向上が得られればよかったのにと思います。

私の経験が他の人に役立つことを願っています。

30
Gray