Galera Cluster の本番運用で知っておきたいこと

# はじめに
[Phone Appli Advent Calendar 2020](https://qiita.com/advent-calendar/2020/pa_engineers) の 25 日目です。メリークリスマス！

この記事では Galera Cluster を本番運用する際に予め覚えておきたい点について記載します。Galera Cluster の導入を検討しているどこかの誰かに良いクリスマスプレゼントになれば幸いです。
※ 本当はもっと書きたいことがありましたが、このレベルの内容でご容赦いただければ。

あくまでも私の知識･経験の範囲内での話になりますが、日本語で書かれたこの辺りのトピックの記事はそう多くないと感じたため、書いてみます。

パブリッククラウドで非常に高い SLA が担保され、運用が楽なマネージドデータベースサービスが隆盛を極める昨今ではありますが、幸か不幸か、Galera Cluster を自前で構築する必要が出た方の参考になることを祈ってます。

そもそも Galera Cluster がどういったものかといった点については以下の記事がよくまとまっているので、これらをぜひご覧下さい。

- [Galera Cluster 導入チェックポイント](https://www.s-style.co.jp/blog/2018/06/1906/)

なお、この記事は MySQL, MariaDB, Percona Server for MySQL などに一定程度慣れた方を対象としております。

# 本番導入にあたって予め理解しておきたい点
## 1. 完全同期だけど同期のタイミングは一致しない
Galera Cluster について調べると「完全同期」や「Synchronous Replication」といったワードがよく出てきます。

これらのワードから、同じタイミングでデータが同期されると受け取ってしまいそうですが、実際にはそうではありません。

より厳密に言うと、同期されたデータが参照できるようになるタイミングが必ずしも一致しないという表現になります。

Galera Cluster の同期は、かなり雑に書くと、以下のような順で行われます。

1. 特定のノードのトランザクションでコミットが発行される。
2. コミットが発行されたノードから write-set というトランザクションの対象レコードのデータを他ノードに伝搬
3. 伝搬されたノードがトランザクションの対象レコードのロックが取れることを確認し、コミットの発生元のノードに応答する。
<br>※ 伝搬されたノードで対象の行のロックが取れなかった場合は、それをコミットの発生元のノードに応答し、そのコミットはデッドロックになる。
4. 各ノードで一斉に書き込みが走る

Galera Cluster では、この 4 の承認されたトランザクションの書き込み処理の「終了タイミング」は Galera Cluster の仕組みの中で保証されません。Galera Cluster では全ノードで承認されたトランザクションによる書き込みの実行はそれぞれのノードに完全に委ねられています。

これが何を意味するかと言うと、同じ行レコードの参照でも、一部のノードでは古いレコードのままといったことが発生します。例えば、ある1つノードが利用する物理ストレージのパフォーマンスが低下してる場合などです。

これの対策は[前述のこの記事](https://www.s-style.co.jp/blog/2018/06/1906/)の「整合性が必要なSELECTの実行」にある2つパターンのいづれかになります。

同期の仕組みについては Galera Cluster の公式の以下の記事が一番わかりやすいかと思います。

- [Certification-Based Replication](https://galeracluster.com/library/documentation/certification-based-replication.html)

## 2. データサイズが大きい場合は全ノード停止はなるべく避けた方が良い
システムを運用しているとメンテナンスなどでシステム停止が必要になる場合があるかと思います。

ただ、Galera Cluster では全ノードの停止(=クラスタ停止)を行う場合、データベースのサイズが数百GB ~ 数TBになる場合は実施の際には注意した方が良いかもしれません。

Galera Cluster では全ノード停止(=クラスタ停止)からの起動を行う場合、最初に起動されるノード以外のノードはデータディレクトリ内の物理ファイルを他ノードから丸ごとコピーする動きをします。

そのため、データベースのサイズが相当に大きい場合は、NW帯域やストレージI/O性能によっては、その同期の完了までかなりの時間を要してしまうケースが考えられます。

データベースのサイズが大きい場合はなるべく 1 ノード毎に停止するオペレーションを検討するのが良いかと思います。

## 3. 更新の負荷分散ソリューションではない
Galera Cluster では各ノードで発生した書き込みを他ノードに伝搬し、全てのノードに理論上同じデータをもたせることで、「高可用性の向上」を狙ったものです。

Galera Cluster のそのレプリケーションの仕様上、書き込みのパフォーマンスは単一ノードのデータベースより劣ります。

参照クエリを各ノードに分散させることで参照のパフォーマンスの向上を図ることは可能ですが、書き込みのパフォーマンス向上はできないので、導入を検討する際はシステムとしてのデータベースの要件についてよく検討した方が良いでしょう。

## 3. I/O 性能重視なら innodb_flush_log_at_trx_commit を 1 以外にする手もある
[innodb_flush_log_at_trx_commit](https://mariadb.com/kb/en/innodb-system-variables/#innodb_flush_log_at_trx_commit) はログバッファからログファイルへの書き込み、ログファイルのディスクへのフラッシュのタイミングを制御するパラメータです。

このパラメータがデフォルトの 1 の場合はコミットのタイミングで「ログバッファのログファイルへの書き込み」と「ログファイルのディスクへのフラッシュ」が行われます。

つまり REDO ログ の整合性のレベルを定義するパラメータとなります。1 以外の 0、2 は 1 と比べ整合性の保証レベルは落ちます。

ただ、Galera Cluster を更新処理が多いシステムで利用する場合、その高可用性を活かして innodb_flush_log_at_trx_commit はせめて 2 を選択することも検討価値のある戦略かと思います。

## 4. フルバックアップは全データベースを対象にすると便利
特に SST (全データの同期処理) に mariabackup を利用する場合にはこの点に注意した方が良いかと思います。

フルバックアップからクラスタを作り直す場合、SST による同期になります。
※ Galera Cluster を運用していてフルバックアップからリカバリーすること自体そうそう無いかもしれませんが。

mariabackup を利用する場合、mysql データベース内のユーザを利用して SST が行われるため、フルバックアップ時の対象データベースをシステムで利用するデータベースだけではなく mysql データベース含めた全データベースを対象としておくと、復旧作業時にユーザを作成する手間が省けます。

また、データのサイズがまだ小さい時期はフルバックアップに mysqldump を利用することが多いかと思います。

この場合、オプションに `--flush-privileges` を追加しておくと権限が mysqldump でバックアップした mysql データベース内のユーザ情報がリストア時に手動で `FLUSH PRIVILEGES` を実行する手間を省けます。

## 5. バイナリログは出力した方が良い
オペレーションミスで誤ってデータベースをドロップしたレコードをデリートしてしまった場合を考慮すると、バイナリログ、いわゆる binlog は Galera Cluster でも出力しておいた方が良さそうです。

ただし、Galera Cluster の場合は binlog のフォーマットは row のみとなるのでご注意下さい。

## 6. SST は特に理由がなければ mariabackup を利用する
Galera Cluster では SST (完全同期、フル同期)の実行方法を rsync, mysqldump, mariabackup などから選択が可能です。特に理由がなければ、mariabackup を選択するのが良いです。
※ Percona XtraDB Cluster であれば xtrabackup になります。

mariabackup は InnoDB テーブルを前提としたバックアップツールで、ストレージエンジンレベルのデータ整合性を担保しつつ、データベースのファイルのバックアップを取得することが可能です。
※ mysqldump のように内部で SELECT 句を発行して取得する論理バックアップではない

そのため、データベースのサイズがかなり大きい場合は mysqldump と比べて、かなり高いパフォーマンスを発揮します。

特に拘った要件が無い限りは mariabackup を選択するのが無難です。

## 7. Galera Cluster の独自ステータスを監視する
Galera Cluster ではクラスタ、ノードの状態を示す独自の[ステータス](https://mariadb.com/kb/en/galera-cluster-status-variables/)が存在します。監視項目としてこれらを使うと良いです。
※ ただ、私の中でこの辺のベストプラクティスはまだありません。

例えば以下のようなものです。
※ よく使われそうなものをピックアップしました。

- `wsrep_ready` 
- `wsrep_local_state`
- `wsrep_cluster_size`
- `wsrep_cluster_status`
- `wsrep_flow_control_sent`
- `wsrep_flow_control_recv`
- `wsrep_flow_control_paused`

また、Galera Cluster の監視方法の観点は以下のように考えると良いと思います。

- クラスタとしての正常性
    - クラスタに参加してるノード数は？
    - クラスタは書き込みを受け付けられる状態？
- ノードとしての正常性
    - このノードは書き込みを受け付けられる状態？
    - ノード間のデータ同期に遅延は起きてない？

## 8. アプリケーションの接続をフェイルオーバーする仕組みが必要
データベースとしての可用性の担保は出来ても、アプリケーションが常にそれを利用できるようにならないとシステムとしての可用性は担保できません。

Galera Cluster を使う場合、ノードのダウン、ノードが書き込みを受け付けなくなったといった場合、アプリケーション側のコネクションをフェイルオーバーする仕組みが必要になります。

比較的導入しやすい方法としてはアプリケーションと Galera Cluster の間に分散装置を配置する方法があります。代表的には以下の OSS があります。

- HAProxy
    - L3 または HTTP 用のロードバランサーとして利用することが多いと思います。
    - mysqlping 相当レベルの監視及び接続の切替が可能です。

- ProxySQL
    - MySQL系データベース用の L7 ロードバランサーです。クエリを読み込んで参照、更新のいづれかによって振り先のノードを切り替えることが可能です。
    - 現在の最新のメジャーバージョンの 2 系からネイティブに Galera Cluster の対応がされています。

また、アプリケーション側のデータベース用のライブラリ、フレームワークの機能に接続をフェイルオーバーする機能があれば、それを利用するのも良いかと思います。

注意するべき一番の点は、MySQL であれば、MySQL のプロセスとして起動していて、接続ができる状態でも、Galera Cluster のノードとしては正常ではないパターンがあることです。

実際の導入時はこの点を一定程度クリアする、または監視でカバーするなどの対策が必要になってきます。

## 9. 自動起動はしないのが無難
Galera Cluster ではその仕組上、例えば、MariaDB の場合は、OS上の MariaDB の自動起動は OFF としておくのが基本です。
※ クラスタレベルのダウン時に意図しないノードから起動することを防ぐため。

そのため、障害時のノード復旧時には手動でプロセスの起動を行う必要があります。

この辺をよしなにやってくれるツールが出てくることに期待してます。
※ お前がつくれ

## 10. ハードウェアの分散
現在はデータベースサーバでは仮想マシンを利用することがほとんどかと思います。Galera Cluster の導入を検討する際は(Galera Cluster だけに限りませんが)物理サーバとネットワークの可用性も考慮したいです。

っというのも、Galera Cluster はその仕様上、ノード間の接続に異常が発生した場合、それぞれのノードが接続可能なノード数がクラスタ全体の過半数を下回っていると判断すると、データ保護のため、そのノードは書き込みを一切受け付けなくなります。

例えば、3 ノードのクラスタを利用し、そのうち 2 ノードを同一筐体上に配置し、この筐体がダウンした場合に残りの 1 ノードは障害が発生した筐体上のノードが復帰するまで書き込みを受け付けなくなります。

そのため、3 ノードのクラスタであれば、それぞれのノードを別々の物理サーバ上に配置したいところです。
※ ネットワーク機器は2重化していることがほとんどかと思いますので触れません。

また、パブリッククラウドの仮想マシン上に Galera Cluster を構築する場合でも同様の観点の考慮が必要になります。アベイラビリティゾーンなどを利用して障害分散できる設計が必要になります。

## 11. Percona と Severalnines のテックブログが役に立つ
最後になりますが、Galera Cluster について調べる際、MariaDB の Galera Cluster または MySQL の Galera Cluster を利用しているに関わらず、以下のブログを調べると便利な情報が多いです。

- [Percona](https://www.percona.com/blog/)
- [Severalnines Database Blog](https://severalnines.com/database-blog)

英語ブログにはなってしまいますが、サーバの構成やパラメータについて、深い考察記事や検証記事が多くあります。

# さいごに
いかがでしたでしょうか。最後まで読んでくださった方とって、良いクリスマスプレゼントになれば幸いです。

それではまたの機会に。メリークリスマス 🎅🎄