この記事では、Redis のマスター/スレーブ アーキテクチャにおけるデータ整合性同期の原理を紹介します。
高可用性には 2 つの意味があります。1 つはデータの損失を可能な限り回避すること、もう 1 つは可能な限りサービスを提供することです。 AOF と RDB はデータの永続性を可能な限り失わないようにするのに対し、マスター/スレーブ レプリケーションは 1 つのデータを複数のインスタンスにコピーを追加して保存します。 1 つのインスタンスがダウンしても、他のインスタンスは引き続きサービスを提供できます。
この記事では、主に、Redis の高可用性テクノロジ ソリューションの 1 つである マスター/スレーブ レプリケーション アーキテクチャ のあらゆる側面について説明します。
この記事はハードコアな記事です。収集してゆっくり味わうことをお勧めします。読者の質が向上すると信じています。間違いがある場合は修正してください、ありがとうございます。 「マ・ゲ・バイト」をフォローして「スター」を設定すると、質の高い記事がいち早く届きますので、読者の皆様のご支援をよろしくお願いいたします。
核となる知識ポイント
問題 = チャンス。問題に遭遇したとき、人は内心とても幸せになります。問題が大きいほど、チャンスも大きくなります。
何事にも値段がある、得もあれば損もあるはず、得もあれば損もあるはずだから、色々なことを気にしなくてもいい、自分が何をしたいのかをしっかり考えればいいのです対価を払って、あとはやってみよう!
#65 兄弟: RDB と AOF を使用すると、ダウンタイムによるデータ損失を心配する必要はなくなりました。 Redis インスタンスが停止しているときに高いパフォーマンスを実現しますか? 利用可能ですか?
1 台のマシンがダウンしてサービスを提供できない場合、他のマシンはどうなるでしょうか?解決できるでしょうか? Redis は、マスター/スレーブ レプリケーションを通じてデータの冗長コピーを他の Redis サーバーにコピーするマスター/スレーブ モードを提供します。
前者をマスター ノード (master)、後者をスレーブ ノード (スレーブ) と呼び、データの複製は一方向であり、マスター ノードからスレーブ ノードへのみ可能です。
デフォルトでは、各 Redis サーバーはマスター ノードであり、マスター ノードは複数のスレーブ ノードを持つことができます (またはスレーブ ノードがない) が、スレーブ ノードが持つことができるマスター ノードは 1 つだけです。
65 兄弟: マスターとスレーブの間でデータの一貫性を確保するにはどうすればよいですか?
レプリカ データの一貫性を確保するために、マスター/スレーブ アーキテクチャでは読み取り/書き込み分離方式が採用されています。
#65 兄弟: なぜ読み書きを分離する方法を使用する必要があるのですか?
マスター ライブラリとスレーブ ライブラリの両方が書き込み命令を実行できると想定できます。同じデータが複数回変更され、それぞれの変更が異なるマスター/スレーブ インスタンスに送信される場合、インスタンスのコピー。データに一貫性がありません。
データの一貫性を確保するために、Redis が複数のインスタンスの変更をロックして調整する必要がある場合、Redis は当然これを実行しません。
65 兄: マスター/スレーブ レプリケーションには他の機能もありますか?
マスター/スレーブ レプリケーションのアクティブ化はスレーブ ノードから完全に開始され、ノード上で何もする必要はありません。マスターノード。
65 兄弟: マスター/スレーブ レプリケーション アーキテクチャを構築するにはどうすればよいですか?
マスター データベースとスレーブ データベース間の関係は、replicaof (slaveof は Redis 5.0 より前に使用されていました) コマンドを通じて形成できます。
スレーブ ノードでマスター/スレーブ レプリケーションを有効にするには 3 つの方法があります。
設定ファイル
の設定ファイルに を追加します。スレーブサーバーのレプリカ <masterip> <masterport></masterport></masterip>
コマンドの開始
redis-server Add --replicaof <masterip> < ;masterport></masterip>
クライアント コマンド
複数の Redis インスタンスを起動した後、クライアント経由でコマンドを直接実行します: replicaof <masterip> < ; masterport></masterip>
の場合、Redis インスタンスはスレーブ ノードになります。
たとえば、インスタンス 1 (172.16.88.1)、インスタンス 2 (172.16.88.2)、インスタンス 3 (172.16.88.3) があると仮定し、インスタンス 2 とインスタンスに対して次のコマンドを実行します。コマンド、インスタンス 2 およびインスタンス 3 はインスタンス 1 のスレーブ ライブラリになり、インスタンス 1 がマスターになります。
replicaof 172.16.88.1 6379复制代码
マスター/スレーブ ライブラリ モードで読み取り/書き込み分離が採用されると、すべてのデータ書き込み操作は 3 つのインスタンスを調整することなく、マスター ライブラリ上でのみ実行されます。 。
マスター データベースに最新のデータが追加されると、マスター データベースとスレーブ データベースのデータの一貫性が保たれるように、マスター データベースはスレーブ データベースに同期されます。
65 兄: マスターとスレーブのデータベースの同期はどのように完了しましたか?マスター データベースのデータはスレーブ データベースに一度に送信されますか? それともバッチで同期されますか?通常の操作中に同期するにはどうすればよいですか?マスター ライブラリとスレーブ ライブラリ間のネットワークが切断された場合、再接続後もデータの一貫性は維持されますか?
65 兄弟、なぜそんなにたくさんの質問があるのですか? 同期は 3 つの状況に分かれています:
#65 兄: めまいがするので、マスターとスレーブ データベース間の最初の同期から始めましょう。
マスター/スレーブ データベースの最初のレプリケーション プロセスは、接続確立フェーズ (準備フェーズ)、マスターからのデータの同期フェーズの 3 つのフェーズに大別できます。データベースからスレーブ データベースへの移行、および同期中に新しいデータを送信するフェーズです。コマンドをスレーブ ライブラリ ステージに書き込みます。;
画像のすぐ上に、全体の全体像が表示されます。詳しくは後ほど紹介します。
この段階の主な機能は、完全なデータ同期の準備としてマスター ノードとスレーブ ノード間の接続を確立することです。 スレーブ ライブラリはマスター ライブラリとの接続を確立します。スレーブ ライブラリは、replicaof を実行し、pync コマンドを送信し、同期が行われることをマスター ライブラリに伝えます。マスター ライブラリが応答を確認すると、マスター ライブラリ間の同期が行われます。マスター ライブラリとスレーブ ライブラリが開始されます。
65 兄弟: スレーブ データベースはどのようにしてマスター データベースの情報を認識し、接続を確立しますか?
スレーブ ノードの構成ファイル内の replicaof 構成項目でマスター ノードの IP とポートを構成すると、スレーブ ノードはどのマスター ノードに接続するかを認識します。
スレーブ ノードは、マスター ノードの IP およびポート情報を保存するために使用される 2 つのフィールド、masterhost および masterport を維持します。
スレーブ ライブラリは replicaof
を実行し、データ同期を実行することを示す psync
コマンドを送信します。コマンドを受信した後、マスター ライブラリは次の指示に従ってレプリケーションを開始します。パラメータ。このコマンドには、メイン ライブラリの runID と copy progress offset という 2 つのパラメータが含まれています。
FULLRESYNC を使用して、2 つのパラメーター (メイン ライブラリの runID とメイン ライブラリの現在のコピー進行状況オフセット) でコマンドに応答します。それをスレーブライブラリに返します。ライブラリからの応答を受信した後、これら 2 つのパラメータが記録されます。
FULLRESYNC 応答は、最初のレプリケーションに使用された完全なレプリケーション を示します。つまり、マスター データベースは現在のデータをすべてスレーブ データベースにコピーします。
マスター ライブラリはデータをスレーブ ライブラリに同期します第 2 フェーズマスターはbgsave コマンドを実行して RDB ファイルを生成し、そのファイルをスレーブ ライブラリに送信します同時に、
メイン ライブラリは各スレーブのレプリケーション バッファを開き、RDB ファイルの生成時から受信したすべての書き込みコマンドを記録します。
65 兄: マスター データベースがスレーブ データベースにデータを同期するとき、リクエストは正常に受け付けられますか?メイン データベースはブロックされません。高速になりたいだけの人として、どのようにして Redis をあらゆる場面でブロックできるでしょうか。 RDB ファイル生成後の書き込み操作は、先ほどの RDB ファイルには記録されていません。マスター/スレーブ データベースのデータの整合性を確保するために、マスター データベースはメモリ内のレプリケーション バッファを使用して、 RDB ファイルの生成とその後のすべての書き込み操作を記録します。
65 兄弟: ライブラリから RDB ファイルを受け取った後、なぜ現在のデータベースをクリアする必要があるのですか?スレーブ ライブラリは、
replcaof コマンドを通じてマスター ライブラリとの同期を開始する前に、マスター データとスレーブ データ間の影響を防ぐために、他のデータを保存する場合があるためです。
レプリケーション バッファとは正確には何ですか?マスター側に作成されたバッファ。以下の 3 周期のマスターデータ書き込み動作すべてが格納されます。 1) RDB を生成するマスター実行 bgsave 中の書き込み操作; 2) マスターが rdb をスレーブ ネットワークに送信する際の書き込み操作; 3) スレーブ ロード rdbデータをメモリに復元する際のファイル書き込み操作。 Redis がクライアントと通信するか、スレーブ ライブラリと通信するかにかかわらず、Redis はデータ対話用にメモリ バッファを割り当てます。クライアントはクライアントであり、スレーブ ライブラリもクライアントです。各クライアントは、 Redis. 最後に、Redis は専用のクライアント バッファを割り当て、すべてのデータ対話はこのバッファを通じて行われます。 マスターはまずデータをこのバッファに書き込み、次にネットワーク経由で送信して、データのやり取りを完了します。
不管是主从在增量同步还是全量同步时,master 会为其分配一个 buffer ,只不过这个 buffer 专门用来传播写命令到从库,保证主从数据一致,我们通常把它叫做 replication buffer。
replication buffer 太小会引发的问题:
replication buffer 由 client-output-buffer-limit slave 设置,当这个值太小会导致主从复制连接断开。
1)当 master-slave 复制连接断开,master 会释放连接相关的数据。replication buffer 中的数据也就丢失了,此时主从之间重新开始复制过程。
2)还有个更严重的问题,主从复制连接断开,导致主从上出现重新执行 bgsave 和 rdb 重传操作无限循环。
当主节点数据量较大,或者主从节点之间网络延迟较大时,可能导致该缓冲区的大小超过了限制,此时主节点会断开与从节点之间的连接;
这种情况可能引起全量复制 -> replication buffer 溢出导致连接中断 -> 重连 -> 全量复制 -> replication buffer 缓冲区溢出导致连接中断……的循环。
具体详情:[top redis headaches for devops – replication buffer] 因而推荐把 replication buffer 的 hard/soft limit 设置成 512M。
config set client-output-buffer-limit "slave 536870912 536870912 0"复制代码
65 哥:主从库复制为何不使用 AOF 呢?相比 RDB 来说,丢失的数据更少。
这个问题问的好,原因如下:
RDB 文件是二进制文件,网络传输 RDB 和写入磁盘的 IO 效率都要比 AOF 高。
从库进行数据恢复的时候,RDB 的恢复效率也要高于 AOF。
65 哥:主从库间的网络断了咋办?断开后要重新全量复制么?
在 Redis 2.8 之前,如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。
从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。
增量复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。
repl_backlog_buffer
断开重连增量复制的实现奥秘就是 repl_backlog_buffer
缓冲区,不管在什么时候 master 都会将写指令操作记录在 repl_backlog_buffer
中,因为内存有限, repl_backlog_buffer
是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。
master 使用 master_repl_offset
记录自己写到的位置偏移量,slave 则使用 slave_repl_offset
记录已经读取到的偏移量。
master 收到写操作,偏移量则会增加。从库持续执行同步的写指令后,在 repl_backlog_buffer
的已复制的偏移量 slave_repl_offset 也在不断增加。
正常情况下,这两个偏移量基本相等。在网络断连阶段,主库可能会收到新的写操作命令,所以 master_repl_offset
会大于 slave_repl_offset
。
当主从断开重连后,slave 会先发送 psync 命令给 master,同时将自己的 runID
,slave_repl_offset
发送给 master。
master 只需要把 master_repl_offset
与 slave_repl_offset
之间的命令同步给从库即可。
增量复制执行流程如下图:
65 哥:repl_backlog_buffer 太小的话从库还没读取到就被 Master 的新写操作覆盖了咋办?
我们要想办法避免这个情况,一旦被覆盖就会执行全量复制。我们可以调整 repl_backlog_size 这个参数用于控制缓冲区大小。计算公式:
repl_backlog_buffer = second * write_size_per_second复制代码
second:从服务器断开重连主服务器所需的平均时间;
write_size_per_second:master 平均每秒产生的命令数据量大小(写命令和数据大小总和);
例如,如果主服务器平均每秒产生 1 MB 的写数据,而从服务器断线之后平均要 5 秒才能重新连接上主服务器,那么复制积压缓冲区的大小就不能低于 5 MB。
为了安全起见,可以将复制积压缓冲区的大小设为2 * second * write_size_per_second
,这样可以保证绝大部分断线情况都能用部分重同步来处理。
65 哥:完成全量同步后,正常运行过程如何同步呢?
当主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,使用长连接的目的就是避免频繁建立连接导致的开销。
在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING 和 REPLCONF ACK。
每隔指定的时间,主节点会向从节点发送 PING 命令,这个 PING 命令的作用,主要是为了让从节点进行超时判断。
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:
REPLCONF ACK <replication_offset>复制代码</replication_offset>
其中 replication_offset 是从服务器当前的复制偏移量。发送 REPLCONF ACK 命令对于主从服务器有三个作用:
检测主从服务器的网络连接状态。
辅助实现 min-slaves 选项。
检测命令丢失, 从节点发送了自身的 slave_replication_offset,主节点会用自己的 master_replication_offset 对比,如果从节点数据缺失,主节点会从 repl_backlog_buffer
缓冲区中找到并推送缺失的数据。注意,offset 和 repl_backlog_buffer 缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。
在 Redis 2.8 及以后,从节点可以发送 psync 命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制。本文以 Redis 2.8 及之后的版本为例。
关键就是 psync
的执行:
从节点根据当前状态,发送 psync
命令给 master:
replicaof
,则从节点发送 psync ? -1
,向主节点发送全量复制请求;replicaof
则发送 psync <runid> <offset></offset></runid>
, runID 是上次复制保存的主节点 runID,offset 是上次复制截至时从节点保存的复制偏移量。主节点根据接受到的psync
命令和当前服务器状态,决定执行全量复制还是部分复制:
slave_repl_offset
之后的数据在 repl_backlog_buffer
缓冲区中都存在,则回复 CONTINUE
,表示将进行部分复制,从节点等待主节点发送其缺少的数据即可;repl_backlog_buffer
缓冲区中 (在队列中被挤出了),则回复从节点 FULLRESYNC <runid> <offset></offset></runid>
,表示要进行全量复制,其中 runID 表示主节点当前的 runID,offset 表示主节点当前的 offset,从节点保存这两个值,以备使用。一个从库如果和主库断连时间过长,造成它在主库 repl_backlog_buffer
的 slave_repl_offset 位置上的数据已经被覆盖掉了,此时从库和主库间将进行全量复制。
总结下
每个从库会记录自己的 slave_repl_offset
,每个从库的复制进度也不一定相同。
在和主库重连进行恢复时,从库会通过 psync 命令把自己记录的 slave_repl_offset
发给主库,主库会根据从库各自的复制进度,来决定这个从库可以进行增量复制,还是全量复制。
replication buffer 和 repl_backlog
レプリケーション バッファは各スレーブに対応し、config set client-output-buffer-limit smile
によって設定されます。
repl_backlog_buffer
はリング バッファです。マスター プロセス全体に 1 つだけ存在し、すべてのスレーブに共通です。 repl_backlog のサイズは、repl-backlog-size パラメータによって設定されます。デフォルトのサイズは 1M です。サイズは、1 秒あたりに生成されたコマンドの合計に基づいて計算できます (マスターが rdb bgsave を実行します) (マスターが rdb をスレーブに送信します) (スレーブ ロード RDB ファイル) 時間 バックログ バッファのサイズを推定します。repl-backlog-size 値は、これら 2 つの積以上になります。
一般に、レプリケーション バッファ
は、マスター/スレーブ ライブラリが完全なレプリケーションを実行するときに、マスター ライブラリ上のクライアントがスレーブ ライブラリに接続するために使用するバッファです。 repl_backlog_buffer
は、スレーブ ライブラリからの増分レプリケーションをサポートするために、書き込み操作を継続的に保存するために使用されるメイン ライブラリの専用バッファです。
repl_backlog_buffer
は専用バッファです。Redis サーバーの起動後、書き込み操作コマンドの受信が開始されます。これはすべてのスレーブ ライブラリで共有されます。マスター ライブラリとスレーブ ライブラリは、それぞれ独自のレプリケーションの進行状況を記録します。そのため、異なるスレーブ ライブラリが回復しているとき、それらは独自のレプリケーションの進行状況 (slave_repl_offset
) をマスター ライブラリに送信し、マスター ライブラリは独立した同期。
図に示すように:
##4. マスター/スレーブ アプリケーションの問題4.1 読み取りと書き込みの分離の問題データの有効期限の問題
65 兄弟: マスター/スレーブ レプリケーションのシナリオでは、スレーブ ノードは期限切れのデータを削除しますか?これは良い質問です。マスター ノードとスレーブ ノード間のデータの一貫性を保つため、スレーブ ノードはデータを積極的に削除しません。 Redis には 2 つの削除戦略があることがわかっています。
#65 兄弟: クライアントはスレーブ ノードからデータを読み取ることで、期限切れのデータを読み取ることになりますか?Redis 3.2 以降では、ノードからデータを読み取るときに、まずデータの有効期限が切れているかどうかを判断します。有効期限が切れた場合、クライアントに返却されず、データは削除されます。 4.2 単一マシンのメモリ サイズ制限Redis の単一マシン メモリが 10 GB に達した場合、スレーブ ノードの同期時間は数分になります。さらにスレーブ ノードがある場合、回復は速度は遅くなります。システムの読み取り負荷が非常に高く、この期間にスレーブ ノードがサービスを提供できない場合、システムに多大な負荷がかかります。 データ量が大きすぎると、完全レプリケーションフェーズ中にマスターノードがフォークしてRDBファイルを保存するのに時間がかかりすぎ、スレーブノードは長時間データを受信できず、タイムアウトがトリガーされます。マスター ノードとスレーブ ノードのデータ同期も、
フル ボリュームに陥る可能性があります。コピー ->タイムアウトによりレプリケーションが中断されます->再接続->フル コピー->タイムアウトによりレプリケーションが中断されます...サイクル。
さらに、マスター ノードの単一マシン メモリの絶対量に加えて、マスター ノードが占めるホスト メモリの割合が大きすぎてはなりません。50% ~ 65% のみを使用するのが最善です。メモリ、30% ~ 45% を残す メモリは、bgsave コマンドの実行やコピー バッファの作成などに使用されます。 概要障害回復は自動化できません。操作 負荷分散ができない; ストレージ容量は 1 台のマシンによって制限されている; これらの問題を解決するには、Sentinel とクラスター の助けが必要です。これについては、後の記事で紹介します。
元のアドレス: https://juejin.cn/post/6973928120332058654著者: Code Brother Byteプログラミング関連の知識については、
プログラミング ビデオ をご覧ください。 !
以上がRedis のマスター/スレーブ アーキテクチャのデータ整合性同期原理を深く理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。