1. マスタースレーブ同期とは何ですか?
マスターとスレーブの同期とは、データの冗長バックアップを意味し、マスター データベース (Master) が自身のデータベース内のデータをスレーブ データベース (Slave) に同期します。
図に示すように、1 つのスレーブ ライブラリまたは複数のスレーブ ライブラリが存在できます。
2. マスターとスレーブの同期はなぜ必要ですか?
Redis には RDB および AOF 永続化テクノロジが備わっていますが、サーバーの再起動時にメモリ内のデータが失われないようにできます (ただし、これはデータが失われないという意味ではなく、再起動時に使用できない状態が残ります)。
しかし、サーバーがシャットダウンして二度と起動しない場合 (ハードウェア障害など)、それはデータが完全に失われたことを意味します。ビジネスに大きな影響を与えることになります。
したがって、マスター/スレーブ同期の必要性は、データの可用性を高めることにあります。これにより、マシンに障害が発生した場合でも、フェイルオーバーに使用できる他のサーバーが確保されます。
問題は、複数のサーバーが同じデータを冗長的に共有するということですが、Redis はデータの一貫性をどのように確保するのでしょうか?
3. Redis はどのようにしてマスターとスレーブの同期を実現しますか?
簡単にまとめると次の2点です。
- すべての変更はメイン ライブラリでのみ行われます。つまり、メイン ライブラリは読み取りと書き込みが可能ですが、スレーブ ライブラリは読み取りのみが可能で書き込みはできません。
- 書き込み操作はマスター データベースからスレーブ データベースに同期されます (完全同期と増分同期)。
(1) 完全同期
1. 接続ネゴシエーションと同期を確立する
1.1 クライアント redis-cli を使用してスレーブ ライブラリに接続し、 replicaof
コマンドを実行して、メイン ライブラリの IP とポートを指定します。
1.2 スレーブ ライブラリが応答したら、メイン ライブラリの runid と レプリケーション オフセット offset を含む psync コマンドを実行します 。
- runid: 起動時にランダムな一意の ID を自動的に生成します。初めて同期するとき、メイン ライブラリの runid は不明なので、
?
; - offset: レプリケーションの進行状況を示します。最初の同期中の値は です
-1
。
1.3 マスター ライブラリが psync コマンドを受信した後、 マスター ライブラリの runid と レプリケーション オフセット offsetFULLRESYNC
の 2 つのパラメーター も含まれるコマンドでスレーブ ライブラリに応答します 。スレーブ ライブラリはこれら 2 つのパラメーターを記録します。
注:replicaof コマンドは、slaveof コマンドと同等です。Redis 5.0 より前では、slaveof コマンドが使用されていました。
2. RDB同期
2.1 メインライブラリが bgsave
コマンドを実行しますが、このとき fork
サブプロセスがRDBファイルを生成し、新しいコマンドがバッファに書き込まれます。
2.2 RDB ファイルをスレーブ ライブラリに送信します。
2.3 データベースからデータを削除した後、RDB ファイルをロードします。
注 1: データの一貫性を確保するために、
bgsave
メイン ライブラリは実行後、スレーブ ライブラリが RDB をロードするまでバッファに新しいコマンドを書き込み続けます。注 2: bgsave は、RDB 生成を独立して担当するサブプロセスを作成します。RDB 生成のプロセス中、Redis メイン ライブラリはブロックされず、メイン ライブラリは通常どおりコマンドを処理できます。
3. コマンドの同期
3.1 RDB のロードが完了すると、スレーブ ライブラリはマスター ライブラリに確認メッセージを返信し、マスター ライブラリはバッファ書き込みコマンドをスレーブ ライブラリに送信します。
3.2 スレーブライブラリはマスタライブラリから書き込みコマンドを受け取り、それを実行してマスタとスレーブのデータを整合させます。
注: コマンドの実行後は、長時間の接続が維持され、マスターとスレーブのデータの一貫性を確保するために書き込み操作コマンドが常に同期されます。
このプロセスは、「長い接続に基づくコマンドの伝播」とも呼ばれます。
(2) インクリメンタル同期
コマンド伝播プロセス中に ネットワーク障害が発生し て接続が切断された場合、その時点では新しい書き込みコマンドはスレーブ ライブラリに同期されません。
ネットワーク接続が切断され、ジッター後に回復した場合でも、この時点では TCP 接続が切断されているため、データは確実に再同期する必要があります。
- Redis 2.8 より前では、スレーブ データベースはマスター データベースとの完全な同期のみを再開でき、RDB ファイルが大きい場合、ネットワークの回復時間は長くなります。
- Redis 2.8 以降、スレーブ ライブラリは増分同期をサポートしており、切断時に発生しなかった書き込みコマンドのみがスレーブ ライブラリに同期されます。
詳細なプロセスは次のとおりです。
- ネットワークが復元された後、スレーブ ライブラリはメイン ライブラリに psync コマンドを発行し、メイン ライブラリから以前に返された runid とコピーされたオフセット offset を伝えます。
- メイン ライブラリはコマンドを受け取ると、runid と offset をチェックし、
CONTINUE
問題がなければコマンドに応答します。 - マスターライブラリはネットワーク切断期間中に書き込みコマンドを送信し、スレーブライブラリはコマンドを受信して実行します。
実際、メイン ライブラリはコマンド伝達プロセス中に 2 つのことを行います。
- 書き込みコマンドをスレーブ ライブラリに送信します。
- 書き込みコマンドは、最近伝播された書き込みコマンドを保持する
repl_backlog_buffer
レプリケーション バックログ バッファーに書き込まれます 。
コピー バックログ バッファはリング バッファです。repl_backlog_buffer に加えて、メイン ライブラリにはレプリケーション ポイント master_repl_offset もあります。
同様に、スレーブ ライブラリにもコピー ポイントslave_repl_offsetがあります。
オフセットがライブラリの psync コマンドで指定されている場合、データは引き続き repl_backlog_buffer バッファーに保存されます。
master_repl_offset - size < smile_repl_offset、つまり、マスター ライブラリの最小オフセットがスレーブ ライブラリのオフセットより小さく、データがまだリング バッファー内にあることを示します。
したがって、メイン ライブラリのバッファーが最新の書き込みコマンド (Redis プロトコル) を収容するのに十分な大きさである限り、ネットワークの中断後に増分同期を使用できます。
デフォルトの repl_backlog_buffer = 1M。書き込まれるデータの量が 1M/s など大きい場合、明らかに、コピー バックログ バッファ データはネットワーク障害の 1 秒後に無効になるため、その値を増やす必要があります。
具体的なサイズは実際の状況に応じて決定する必要があります。Redis サーバーの起動にもある程度の時間がかかるため、10M 以上に設定することをお勧めします (おそらく 10 秒以内に中断される可能性があります)。