なからなLife

geekに憧れと敬意を抱きながら、SE、ITコンサル、商品企画、事業企画、管理会計、総務・情シス、再び受託でDB屋さんと流浪する人のブログです。

HammerDB 4.0がリリースされていた - 複数インスタンスへの接続・負荷試験 その1

HammerDB 4.0がリリースされていた - リリースノートチェック - なからなLife
HammerDB 4.0がリリースされていた - 環境構築 - なからなLife
HammerDB 4.0がリリースされていた - 設定まわりの変化 - なからなLife
HammerDB 4.0がリリースされていた - ワークロードの実行 - なからなLife
の続きです。

新機能へのトライ

割と大きな新機能のはずなのに、リリースノートに出てこない、「クラスター構成における複数インスタンスへの接続・負荷試験」の機能に挑戦します。

手がかりは、ドキュメントの
https://hammerdb.com/docs/ch04s05.htmlとhttps://hammerdb.com/docs/ch04s06.html#d0e1777
、公式ブログの
https://www.hammerdb.com/blog/uncategorized/hammerdb-v4-0-new-features-pt4-connect-pooling-for-clusters/
くらいですね。

DB側の構成

マルチライター構成にも、ライター/リーダー構成にも対応しているらしいので、今回は以下の2つに対して試してみます。
(1)AWS RDS/MySQL 8.0.21 ソース/リードレプリカ構成。各1台、計2台
(2)AWS Aurora MySQL 5.7 Compatibirity マルチマスター/リードレプリカ構成。計3台。

マルチライター構成は、OracleRACを念頭に置いているんじゃないかと思っていたりはしますが、環境作るのめんどくさいので。。。

HammerDB側の設定

コネクションプールの有効化

dictの設定で、通常と異なる必須設定は以下の2つです

mysql_prepared         = true
mysql_connect_pool     = true

mysql_connect_poolを「true」設定ファイルを読み込んで、DBクラスターを構成する各インスタンスにコネクションプールを作成、設定内容に基づいてワークロードをどのセッションからリクエストするかを制御するモードにシフトします。

なので、先に、設定ファイルを編集しておく必要があります。


HammerDB GUIを使用する場合も、GUI側でこの設定を編集することはできないので、設定ファイルを編集した上で、GUI上の「Driver Options」から「XML Connect Pool」のチェックボックスをONにします。



mysql_preparedについては、ドキュメント上、非常にわかりにくいところに

7.2. MySQL Prepare Statements
With MySQL there is the option to use server side prepared statements. This option is mandatory if using the XML connect pool feature.
(Google翻訳)
MySQLには、サーバー側のプリペアドステートメントを使用するオプションがあります。 XML接続プール機能を使用する場合、このオプションは必須です。
https://hammerdb.com/docs/ch04s07.html

とあるので、この試験を実施する上ではtureにするのですが、全シナリオ、trueにしようがfalseにしようが、見た目の挙動は一緒でした。
なんだこれ、と思ってソースをちょっと覗き込んでみたら、

mysql_connect_pool = true
の場合、内部で強制的に
mysql_prepared = true
なモードに変えていました。

ので、特に意識して設定する必要はなさそうです。。。




設定ファイルの解説

DBクラスターを構成するインスタンスに関する設定は、以下の場所にDBMS種別ごとにxmlファイルで存在しています。

$ ll /home/ec2-user/HammerDB-4.0/config/connectpool
total 20
-rwxr-xr-x 1 ec2-user ec2-user  977 Jul  8  2020 db2cpool.xml
-rwxr-xr-x 1 ec2-user ec2-user 2459 Jul  8  2020 mssqlscpool.xml
-rwxr-xr-x 1 ec2-user ec2-user 1343 Jul  8  2020 mysqlcpool.xml
-rwxr-xr-x 1 ec2-user ec2-user  956 Jul  8  2020 oracpool.xml
-rwxr-xr-x 1 ec2-user ec2-user 1091 Jul  8  2020 pgcpool.xml

ec2-userのホームディレクトリにHammerDBをインストールしたので、この場所にDBMS種別ごとの設定ファイルがあります。

今回は、MySQLの試験なので、「mysqlcpool.xml」を使います。



まずはデフォルト状態の中身を確認。

$ cat mysqlcpool.xml
<connpool>
<connections>
    <c1>
        <mysql_host>host1</mysql_host>
        <mysql_port>5432</mysql_port>
        <mysql_socket>/tmp/mysql.sock</mysql_socket>
        <mysql_user>root</mysql_user>
        <mysql_pass>mysql</mysql_pass>
        <mysql_dbase>tpcc</mysql_dbase>
    </c1>
    <c2>
        <mysql_host>host2</mysql_host>
        <mysql_port>5432</mysql_port>
        <mysql_socket>/tmp/mysql.sock</mysql_socket>
        <mysql_user>root</mysql_user>
        <mysql_pass>mysql</mysql_pass>
        <mysql_dbase>tpcc</mysql_dbase>
    </c2>
    <c3>
        <mysql_host>host3</mysql_host>
        <mysql_port>5432</mysql_port>
        <mysql_socket>/tmp/mysql.sock</mysql_socket>
        <mysql_user>root</mysql_user>
        <mysql_pass>mysql</mysql_pass>
        <mysql_dbase>tpcc</mysql_dbase>
    </c3>
</connections>
<sprocs>
        <neworder>
                <connections>c1 c2 c3</connections>
                <policy>round_robin</policy>
        </neworder>
        <payment>
                <connections>c1 c2 c3</connections>
                <policy>round_robin</policy>
        </payment>
        <delivery>
                <connections>c1 c2 c3</connections>
                <policy>round_robin</policy>
        </delivery>
        <stocklevel>
                <connections>c1 c2 c3</connections>
                <policy>round_robin</policy>
        </stocklevel>
        <orderstatus>
                <connections>c1 c2 c3</connections>
                <policy>round_robin</policy>
        </orderstatus>
</sprocs>
</connpool>

「connections」ブロックと、「sprocs」ブロックに分かれています。


「connections」は、各インスタンスへの接続情報の定義です。
公式ブログによると、接続数に上限はない、とのことです。


※定義名(c1とかc2)の方は、勝手に変えられるんだろうか。。。


にしても、MySQL用のテンプレートファイルなのに、portが3306じゃなくて5432になっているとか、どうなのよ。。。



「sprocs」には、TPC-Cワークロードの実装となっているストアドプロシージャの名前が列挙されていて、それらをどのConnection経由で実行するかを紐付けます。

各ストアドプロシージャの中身は、

  • 更新あり
    • neworder
    • payment
    • delivery
  • 参照のみ
    • stocklevel
    • orderstatus

となっていますので、クラスター構成/接続情報に応じて、紐付けを行います。


リードレプリカへのセッションから「更新あり」のストアドプロシージャを呼び出さないようにするのがポイントですね。

「マルチマスタでリードレプリカ無し」とか「Oracle RAC」なら区別不要ですね。
あるいは、「Active Data Guard DML Redirect」なんかだと、あえてWriterじゃないインスタンスにも更新リクエスト投げてもいいかも。※Redisどうなるんだろ。


policy要素は、リクエスト先として指定されているconnectionsに対して、どのようなルールでリクエストを分散するかのルールです。

  • first_named
  • last_named
  • random
  • round_robin

下2つはそのまんまです。

実際に試験する

以下の試験を試してみます。


「mysqlcpool.xml
のうち、connections部は、それぞれ固定で、sprocs部を微調整していきます。


(1)MySQL ソース1:レプリカ1構成

(1-1)すべてソース側に振る構成(レプリカへの接続設定は入れつつ、リクエストを投げない)
(1-2)参照のみはすべてリードレプリカ、更新ありはソース側に振る構成
(1-3)参照のみは2台に、更新ありはソース側に振る構成
(1-4)更新も双方に(エラーになるはず)
を試します。

Aurora MySQL マルチマスター(2台)構成

(2-1)更新も参照も全台に
を試します。
それ以外は、上記で済んでるはずなので。

また、コネクションプールを使うので、Auroraのクラスターエンドポイントやリーダーエンドポイントではなく、インスタンスエンドポイントを使うことにします。
今回はリーダー1台ですが、クラスター/リーダーエンドポイントはそれ自体がラウンドロビンのロードバランスを行うエンドポイントなので、コネクションプールセッションを確立する時点で宛先が確定します。



設定一覧
設定項目a 設定項目b 設定項目c 試験1-1 試験1-2 試験1-3 試験1-4 試験2-1
connections c1 mysql_host ソースインスタンスのエンドポイント 同左 同左 同左 ライターインスタンス1のエンドポイント
mysql_port 3306 同左 同左 同左 同左
mysql_socket /tmp/mysql.sock(不要) 同左 同左 同左 同左
mysql_user tpcc 同左 同左 同左 同左
mysql_pass tpcc 同左 同左 同左 同左
mysql_dbase tpcc 同左 同左 同左 同左
connections c2 mysql_host レプリカインスタンスのエンドポイント 同左 同左 同左 ライターインスタンス2のエンドポイント
mysql_port 3306 同左 同左 同左 同左
mysql_socket /tmp/mysql.sock(不要) 同左 同左 同左 同左
mysql_user tpcc 同左 同左 同左 同左
mysql_pass tpcc 同左 同左 同左 同左
mysql_dbase tpcc 同左 同左 同左 同左
connections c3 mysql_host なし 同左 同左 同左 レプリカインスタンスのエンドポイント
mysql_port なし 同左 同左 同左 3306
mysql_socket なし 同左 同左 同左 /tmp/mysql.sock(不要)
mysql_user なし 同左 同左 同左 tpcc
mysql_pass なし 同左 同左 同左 tpcc
mysql_dbase なし 同左 同左 同左 tpcc
sprocs neworder connections c1 c1 c1 c1 c2 c1 c2
policy round_robin 同左 同左 同左 同左
payment connections c1 c1 c1 c1 c2 c1 c2
policy round_robin 同左 同左 同左 同左
delivery connections c1 c1 c1 c1 c2 c1 c2
policy round_robin 同左 同左 同左 同左
stocklevel connections c1 c2 c1 c2 c1 c2 c1 c2
policy round_robin 同左 同左 同左 同左
orderstatus connections c1 c2 c1 c2 c1 c2 c1 c2
policy round_robin 同左 同左 同左 同左

sprocsのconnectionsだけは、同左を使わず、違いを見やすいようにしています。

結果

ConnetionPoolによる負荷分散を有効にし、リーダーに負荷をかけるような設定で走らせたら、以下のようなエラーが大量出力されて、まともに計測ができませんでした。

Vuser 5:mysqlexec/db server: Unknown prepared statement handler (ostat_st) given to EXECUTE
Vuser 5:mysqlexec/db server: Unknown prepared statement handler (delivery_st) given to EXECUTE


AuroraのWriter 1:Reader 1構成のものに対して実行しても一緒でした。。。


なお、PostgreSQLだと動きます。。。

GitHubにIssue上げてみた!

バグでした!
Google翻訳さんとDeepLさんに頑張ってもらって2時間くらい?かけて久々の英作文してIssue登録したら、あっさりバグ認定されて翌朝には修正版のプルリクが上がってました。
暫定対処法も書いてありました。ありがたい!

Error when running TPC-C MySQL with XML Connection Pool in HammerDB v4.0 · Issue #216 · TPC-Council/HammerDB · GitHub


PostgreSQLにもやってみた

詳細省略しますが、期待通りに動きます!(雑
パラメータの名前がちょっと違うだけで、MySQLとやることは同じです。
Aurora PostgreSQLにはマルチマスターはないけどね。




まとめ

  • MySQLに対してHammerDB 4.0の新機能でリードレプリカにも負荷をかけようとすると、エラーが出まくる。バグだったので、GitHub見て暫定対処するか次のリリース待ち!

というわけで、次のリリースが出る前に、暫定対処でソース直接書き換えた版でのテストを次回のエントリで!