複数のMySQL サーバーのデータを同期するための仕組み
MySQLのレプリケーションの仕組み
1. マスターとスレーブに同一のデータを用意 2. マスターに更新SQLを実行 3. マスターからスレーブに更新SQLの内容を転送 4. スレーブが転送された更新SQLの内容をリプレイ
「結果整合性モデル」でレプリケーションは動作する。 「結果整合性モデル」= 一貫性があるとは言い切れない。
特性 | 非同期レプリケーション | グループレプリケーション | 備考 |
---|---|---|---|
スレープの性能や負荷がマスターに影響を及ぼさない | Yes | No | バッチ専用スレーブ、バックアップ専用スレープなどは非同期レプリケーションが有利 |
自動フェイルオーバー | No | Yes | アプリケーションからの接続先まで自動で切り替えるにはMySQL Routerとの連携が必要 |
更新のレイテンシー | 低い | 高い | ただし、どちらもレプリケーション遅延は起きうる |
系全体としてのデータ保護の堅牢性 | オペレーションに依存 | 高い | 正しいオペレーションのもとでは両者の堅牢性はほぼ同等 |
非同期レプリケーションのデータ同期
マスター
クライアントから受け取った更新SQLの内容をマスター上のデータに反映して、バイナリログ(ビンログ)ファイルに記録(バイナリログイベントと呼ぶ)
Binlog Dump (Binlog Sender)と呼ばれるスレッドが待機しており、このスレッドがバイナリログの更新を検知してスレーブにバイナリログイベントを送信する。マスターと接続しているスレーブに1対1で常駐。
スレーブ
Binlog Dump スレッドに対応する形でスレーブの I/O(Binlog Receiver)スレッドが起動している。 この2つのスレッドがTCP通信でコネクションからバイナリログイベントが送信されてくると、I/Oスレッドが受信してリレーログと呼ばれるファイルに記録する。
また、リレーログの更新を待ち受ける SQL(Binlog Applier)スレッドが常駐している。 これがリレーログからバイナリログイベントを取り出し、スレーブ上のデータに対してリプレイすることで、マスターとスレープのデータが同一となる。
SQLスレッドは slave_parallel_workers オプションによって、リレーログに記録されたバイナリログイベントを並列で適用できる。 2つ以上に設定された状態をマルチスレッドスレーブと呼ぶ。
バイナリログフォーマット
MySQLはバイナリログイベントを「マスターが受け付けた更新SQLそのもの」として記録する方式(binlog_format = STATEMENT)がデフォルトだった。 -> 1行のSQLとして記録されるためコンパクトだけど、更新前の行の情報をいっさい保持しないため、万一「マスターとスレープでデータに不合が発生」しており「マスターで実行された更新 SQLとスレープでリプレイされたバイナリログイベントの更新した行の数が違って」いてもそれを検出できない。
これに対して、最近はバイナリログイベントを「マスターが受け付けた更新 SQLで更新された行の情報」とするのがデフォルト(binlog_format = ROW)となっている ★これが8系になるタイミングでやりたいこと -> 更新された行の情報が記録されるため、100万行を更新するステートメントであれば100万のバイナリログイベントが作成される。更新前の行を1行ずつ検索して対象の行を特定するため、不整合があった場合はSQLスレッドにエラーを発生させられる。
「マスターとスレーブでカラムの数やデータ型が違ってもレプリケーションが組める」という柔軟さがある。
1行の単純なINSERTステートメントでは大きな違いはないが、UPDATE、DELETE や INSERT ...SELECT... 形式で 1ステートメントが複数行を更新する場合はファイルサイズなどに大きな違いが生まれる。
※ どちらにしても、トランザクションによる保護は行われるため、分割されても一貫性には問題はない。
ROWはDML (INSERT/UPDATE/DELETE など)のみ有効。DDL (CREATETABLEやALTER TABLE など)は常にSTATEMENTで記録。