ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

Galera Clusterの同期の仕組みを公式ドキュメントから読み解く(8) WEIGHTED QUORUM

はじめに

Technical Description、8回分のようやく最後です!

Technical Description — Galera Cluster Documentation

take-she12.hatenablog.com

take-she12.hatenablog.com

take-she12.hatenablog.com

take-she12.hatenablog.com

take-she12.hatenablog.com

take-she12.hatenablog.com

take-she12.hatenablog.com

WEIGHTED QUORUM

単一ノードが故障することに加えて、ネットワーク障害によってクラスタが分断されることもあるでしょう。お互いに接続されているノード集合であるコンポートネントは、一方で他のコンポーネントとは異なる状態です。このような状況では、データベースの歴史的な相違を避けるために、ある1つのコンポーネントのみが操作を継続すべきです。このコンポーネントはPrimary Componentと呼ばれます。

通常の操作では、Primary Componentはクラスタそのものです。クラスタ分断が起きた時、Galera Clusterは特別なquorumアルゴリズムを用いて1つのコンポーネントをPrimary Componentとして選択します。これによってクラスタ内で1つ以上のPrimary Componentが存在しないことを保証します。

注意:ノードが独立することに加えて、quorumはgarbdと呼ばれる切り離されたプロセスを用いて計算します。

WEIGHTED QUORUM

現在のクラスタ内のノード数は現在のクラスタサイズを定義します。すべての利用可能なクラスタノードのリストを定義するconfiguration設定は存在しません。クラスタにノードが加入するたびにクラスタサイズは増加します。ノードがクラスタから離脱したときはクラスタサイズは現象します。クラスタサイズはquorumを達成するために必要な投票数を決定します。

Galera Clusterはノードの応答がなく、クラスタからの分断が疑われる時はいつでもquorumの投票が行われます。evs.suspect_timeoutパラメタを用いてレスポンスのタイムアウト時間を調整することができます。デフォルトは5秒です。

クラスタがquorum投票を行う時、切断前から接続されたノードの大多数が残っていた場合、それらは残ります。ネットワーク分断が起きると、切断の両側でアクティブなノードが残ります。コンポーネントはPrimary Componentとして独立して操作され続けますが、quorumに達せないコンポはnon-primary状態になってPrimary Componentと接続しようとします。

Quorumは過半数を必要とします、これは2つのクラスタで自動的にフェイルオーバーできないことを意味します。あるノードの故障がノードを自動的にnon-primary状態にし続けるからです。

偶数ノードを持つクラスタはsplit-brainを引き起こすリスクが存在します。もしネットワーク分断が起きた場合、その分断がノードをちょうど半分に分断してしまうので、どちらのcomponentもnon-primary状態になってしまいます。

自動的なフェイルオーバーを行うためには、少なくとも3つのノードが必要です。同様の理由から、これはインフラストラクチャの他のレベルの拡張されることを注意してください

  • 単一のスイッチクラスタは最低3ノード必要
  • スイッチにまたがるクラスタは最低3スイッチ必要
  • ネットワークをまたがるクラスタは最低3ネットワーク必要
  • データセンタをまたがるクラスタは最低3データセンタ必要

Split-brain Condition

お互いに自律的に動くデータベースクラスタ障害は、split-brainと呼ばれます。これが起きると、2つのデータベースノードで同じテーブルの同じレコードを更新することにより、データが回復不能になります。quorumベースのシステムの場合のように、Galera ClusterはPrimary Componentを選択する際にquorumアルゴリズムが失敗したときにsplit-brainが発生します。

例えば、メインスイッチが故障中し、バックアップスイッチを持たないクラスタを使っているとき、(split-brainは)発生します。または、2つのノードのクラスタであるノードが故障したときも発生します。

設計によって、split-brainは回避できます。分断されたクラスタが2つとも同じサイズになった場合、(明示的に設定しない限り) どちらの分断されたcomponentもPrimary Componentになりません。

偶数のノードでのリスクを最小限にするためには、常にあるコンポーネントがprimaryになるように分割しましょう。

この分割例では、障害によって正確にノードが半数になることは難しいでしょう。

QUORUM CALCULATION

Galera Clusterは重み付けquorumをサポートしています。各ノードに0から255の範囲で重みをつけることができます。

これは、新しいコンポーネントのノードの重みの合計が前のPrimary Componentの半数から正常に残ったノードを除いた数を超えた場合にquorumを保持されることを意味します。

ノードの重みをpc.weightパラメタで設定できます。デフォルトでは1であり、ノード数と同じになります。

注意:pc.weightパラメタは動的に変更できます。 Galera Clusterでは新しい重みは重みを運ぶメッセージ配信によって適用されます。瞬間的には、新しい重みを知らせるメカニズムはありませんが、結果的にはメッセージが配布されると発生します。

注意:警告:重みの変更メッセージが配布されたとき、一時的にグループ分断が起きると、重みを配信したすべての分割されたコンポーネントはnon-primaryになります。通常メッセージを配信する分割(パーティション)は状態遷移が配達された時に重みが適用され、quorumが仕切られるでしょう。 言い換えると、分断が発生した瞬間、重み変更メッセージが送信されるなら、一時的にクラスタのすべてがNon-Primaryになり得るということです。この状況を復旧するには、再マージを待つか、どのパーティションがもっとも進んでるかを調べ、bootstrappingによって新しくPrimary Componentとして起動します。

WEIGHTED QUORUM EXAMPLES

重み付けquorumがどのように動くか理解するために、いくつかの例を紹介しましょう。

Weighted Quorum for Three Nodes

3ノードでquprumの重みを設定するなら、以下のパターンを用います。

node1: pc.weight = 2
node2: pc.weight = 1
node3: pc.weight = 0

このパターンでは、node2とnode3が同時に殺されると、node1がPrimary Componentになります。node1を殺すとnode2とnode3はnon-primary componentsになります。(訳注:これってつまりnode1が常に死なないようにしないとまずいよね?なんでこんなことするんだろう)

Weighted Quorum for a Simple Master-Slave Scenario

単純なmaster-slaveのシナリオなら以下のパターンを使います。

node1: pc.weight = 1
node2: pc.weight = 0

このパターンでは、もしmasterが死んでも、node2はnon-primary componentとなります。しかし、node2が死んでも、node1はPrimary Componentであり続けます。network接続がnode間で失われても、node1はPrimary Componentであり続け、node2はnon-primary componentとなります。

Weighted Quorum for a Master and Multiple Slaves Scenario

複数のslaveを持つmaster-slave構成の場合は、以下のようになります。

node1: pc.weight = 1
node2: pc.weight = 0
node3: pc.weight = 0
...
noden: pc.weight = 0

このパターンでは、ノード1が死んでも、すべてのノードはnon-primaryになります。他のノードが死んでも、Prymary Componentは(node1に)保持されます。ネットワークが分断しても、node1が常にPrimary Componentであり続けます。

Weighted Quorum for a Primary and Secondary Site Scenario

primaryとsecondaryのサイトを持つ場合のquorumの重み付けは以下になります。

Primary Site:
  node1: pc.weight = 2
  node2: pc.weight = 2

Secondary Site:
  node3: pc.weight = 1
  node4: pc.weight = 1

このパターンでは、いくつかのノードはprimaryサイトに配置され、他のいくつかはsecondaryサイトに配置される。secondaryサイトがダウンまたはサイト間でネットワークが切断されたとき、primaryサイトのノードはPrimary Componentであり続けます。加えてnode1とnode2どちらかクラッシュした場合、残りのノードはnon-primary componentになります。

おわりに

重み付け、結構有用だなーって思いました。

単純に今は重み付けなしで、マルチマスタでやっていて、HAProxyでsingleマスタにしたりしています。

やーっとTechnical Descriptionが全部終わりました。必要な語彙はだいたい揃ったと思います。

しかし実際の運用となると、Technical Descriptionからも多く参照されているConfigurationの章も読まないとなーと思ったので、まだ続きます。。。