スマートスタイル TECH BLOG

データベース&クラウド技術情報

MySQL Router 8.2.0 Read Write Splitting 機能 について

MySQL Innovation Release 8.2.0 より、 MySQL Routerに待望の Read/Write Splitting 機能が追加されました。

類似の機能は MariaDB MaxScaleではすでに実装されていた り、 ProxySQLではユーザが設定すれば実現できた りしましたが、やっとMySQL Routerにも来たか…!という感じです。

今回はこの機能を検証してみたいと思います。

Read/Write Splitting とは

Read/Write Splitting とは MySQL Router のルーティング候補の選択方法の一つです。

MySQL の従来からの非同期レプリケーションは、書込みが可能なプライマリノードが一つだけ存在し、そこからデータの複製(レプリケーション)を行うレプリカノードが複数ある、という構成になります。

レプリカノードは、負荷分散(+フェイルオーバ候補/バックアップ)のために利用するのが一般的であり、実現のためにはロードバランサとなるSW or HWを利用することになります。

しかしながら、一般的なロードバランサは実行された処理が 更新系の処理 なのか 参照系の処理 なのか判断してルーティングする機能はありません。

そのためロードバランサの疑似IPやポート番号ごとにプライマリ用、レプリカ用というように分け、アプリケーション主導で使い分けるというのが通常です。

MySQL Routerもこれまでは基本的に上記の動作となっていました。

Read Write Split Routing 機能は、 SQLが更新系なのか参照系なのかをMySQL Routerが判断して適切な候補ノードに処理を振り分ける というものです。

これによってアプリケーション側から意識せずにレプリケーション環境を適切に使用する事ができます。

MySQL Routerのルーティングの設定

MySQL Router は設定ファイル(デフォルト: /etc/mysqlrouter/mysqlrouter.cnf) の個々の routing セクションにルーティング方法を定義します。

v8.1.0以前は、大きくはroutingセクション内の2つのオプションでルーティング先を決めていました

オプション 説明
destinations ルーティング候補
routing_strategy ルーティングの候補の選択基準

Read/Write Splitting も、 routing_strategy の選択肢なのかと思いきや、 access_mode という第三の基準が導入され、これによって実現されます。

access_mode はデフォルトで設定されておらず auto を設定するとRead/Write Splittingが有効になります。

機能を使うにはその他、以下のパラメータを有効化する必要があります。

とは言えマニュアルで設定する事はほぼありません。
mysqlrouterのbootstrap(初期設定)時にRead/Write Splitting 用設定が自動的に追加されます。

https://dev.mysql.com/doc/relnotes/mysql-router/8.2/en/news-8-2-0.html

読み取り/書き込み分割はデフォルトで有効になっています。新しいセクション が [router:read_write_split]ブートストラップ設定に自動的に追加されます。この設定を無効にするには、 を使用してブートストラップする必要があります –disable-rw-split。

デフォルトでは 6450 ポートが使用されます。

注意点として、destinations=metadata-cache が必須のため、 対象は InnoDB Cluster、または InnoDB ReplicaSet である必要があります。

Read/Write Splittingの動作確認

まずは簡単に動作を確認してみます。

検証環境には 3台構成(blog1(プライマリ), blog2/blog3(レプリカ))の InnoDB ReplicaSet を使用し、1台のmysqlrouter(blog4)を使用します。

SQLが更新系なのか参照系なのかは、実行したSQL構文によって判断されます。

SELECTから始まるクエリであればレプリカにルーティングされ、BEGINから始まるクエリであればプライマリにルーティングされ、その後のトランザクション内の処理はSELECTでもプライマリにルーティングされるはずです。

詳しくは以下を参照ください。

https://dev.mysql.com/doc/mysql-router/8.2/en/router-read-write-splitting-statements.html

想定通りの動きとなりました。

一つの接続の中で、明示的にプライマリノードへ処理をルーティングしたり、レプリカノードに処理をルーティングする指定も可能です。

これは、 ROUTER SET という新しく実装されたコマンドによって行います。

基本的には Read/Write Splitting によってルーティング先は判断されますが、構文で判断している以上、複雑なSQLが意図しない候補にルーティングされるというようなエッジケースは発生し得ます。
そのような場合でもユーザ側で簡単にルーティング先を切り替えられるようになっているようです。

なお、一つの接続あたりには 1つのプライマリと1つのレプリカが割り当てられますので、SET ROUTERread_only に切り替えても接続内ではロードバランスされない点にご注意ください。

https://dev.mysql.com/doc/mysql-router/8.2/en/router-read-write-splitting.html

Each client session can communicate with one read_write and one read_only destination.

Read/Write Splittingにおける参照系処理の待機

SET ROUTER コマンドで設定できるオプションとして、 access_mode の他に、wait_for_my_writeswait_for_my_writes_timeout が追加されています。

ドキュメントの和訳は以下の通りですが、少しわかリ辛いかもしれません。

wait_for_my_writes

タイプ 整数
デフォルト値 1
最小値 0
最大値 1
読み取り専用クエリは、最後に書き込まれたトランザクションを待ちます。

セクション3.5「読み取り/書き込みの分割」 を参照してください。

wait_for_my_writes_timeout

タイプ 整数
デフォルト値 1
最小値 0
最大値 4294967295
読み取り専用の宛先が書き込まれたトランザクションを適用するまで待機する最大時間 (秒)。その後、読み取り専用の宛先にフォールバックします。

Read/Write Splittingが有効なセッションでは、(トランザクションを明示的に開始していない限り)更新はプライマリに、参照はレプリカにルーティングされます。
一方、非同期レプリケーション環境ではプライマリに実行した更新がレプリカに到達するまでにタイムラグがありますので、自分で更新したと思っていたデータが後ほどの参照で更新されていないような事がおきるケースがあります。
そのようなケースの防止策がこれらのオプションになります。

wait_for_my_writes は、更新処理に続く参照処理を実行する時に、先に実行された更新処理がレプリカに反映されるまではプライマリノードへ参照処理を行う という動作を有効にします。

wait_for_my_writes_timeout は、プライマリへルーティングするかどうかを待機する時間のタイムアウト(秒)になります。

試してみましょう。

検証のため参照系で遅延レプリケーションを有効にします

更新・参照クエリを連続実行してみると、insertしたデータが遅延レプリによりまだ到達しないので、Empty setになります。

wait_for_my_writes を設定してみると、先の更新がレプリカに反映するまでプライマリにルーティングされる様子が確認できます
wait_for_my_writes_timeout のデフォルトは1ですが、プライマリにルーティングされるまでに2秒の待機が発生しました。

まとめ

MySQL Routerに Read/Write Splitting 機能がやってきたことで、よりアプリケーションから透過的にデータベースクラスタをスケールアウトする事が可能になりました。

今後もMySQL Routerの新機能に注目していきたいと思います!

Return Top