Redis バージョンの新機能によって引き起こされるマスター/スレーブ切り替えの失敗に注意してください

バックグラウンド

最近、ビジネス Redis データのグループが増加し続けているため、メモリの拡張が必要になり、メモリの拡張にはクラウド ホストの再起動が必要になります。計画された拡張とアップグレード中に、誤ってマスターとスレーブの切り替えが発生し、データ損失とマスターの障害が発生しました。読み取り専用状態が発生しました。ここに共有する記録があります。

ビジネス Redis 高可用性アーキテクチャ

このビジネスRedis群は1マスター、1スレーブを使用し、センチネルクラスターによる障害発生時の自動マスター・スレーブ切り替えを実現しており、数年にわたり実戦テストを重ね順調に稼働しているアーキテクチャです。

高可用性アーキテクチャは、一般的に次の図に示されています。

高可用性を実現するためのセンチネルの原理について簡単に説明します。

クラスター内の複数の (2n+1、N>1) センチネルは、Redis のすべてのマスター/スレーブ ノードを定期的にポーリングします。センチネル クラスター内のセンチネルの半数以上が、主観的に Redis ノードがオフラインであると判断した場合、それが判断されます対応する処理のために客観的にオフラインになります。

  • オフライン ノードがマスターの場合は、正常に動作しているスレーブを新しいマスター ノードとして選択します。

  • オフラインノードがスレーブの場合は、スレーブノードから削除します。

客観的にオフラインだったノードが正常に戻った場合、センチネル内のセンチネルの半数以上が確認後にそのノードを利用可能なスレーブ ノードに追加し直します。

Redis の読み取りと書き込みが必要なすべてのサーバーは、Redis のマスター/スレーブ構成を直接書き込む必要はありませんが、sentinel にアクセスすることで Redis の現在のマスター/スレーブの可用性ステータスを取得します。特定の実装方法では、更新について定期的に Sentinel にクエリを実行できます。 let Sentinel be in マスター/スレーブが変更されたときに更新するようにサブスクライバーにアクティブに通知します。

高可用性を実現するためのセンチネルの詳細な原​​理についてはここでは繰り返しませんが、興味のあるパートナーは参考資料の関連情報に移動してください。

特定のメモリ拡張プロセス

Sentinel は、障害が検出されたときに Redis のマスターとスレーブを自動的に切り替えることができます。また、Sentinel failed over mastername コマンドをアクティブに実行してマスターとスレーブを手動で切り替えることもできるため、メモリ拡張と再起動のプロセスは次のように設計されています (A は、初期マスターが配置され、B は初期スレーブを表します。クラウド ホスト):

  1. ホスト B のメモリ構成をアップグレードし、ホスト B を再起動します。

  2. B の Redis スレーブが再起動後にマスター データを再同期したかどうかを確認します。以下の内容を確認します。

  • 2.1 スレーブ Redis ログが異常かどうかを確認します。異常パスはありません

  • 2.2 info keyspace コマンドを使用して、マスターとスレーブの db キーの数が一致しているか、異常なパスがないかを確認します。

  • 2.3 マスターにテストキーを書き込み、スレーブで同期が成功するか確認する

  • 2.4 依存サーバのログに異常がないかを監視する

  1. Sentinel failed over mastername コマンドを使用してマスターとスレーブを手動で切り替えます。ホスト A が新しいスレーブになり、ホスト B が新しいマスターになります。これまでの手動切り替えの経験によれば、この時点では基本的に安定しています。通常のマスター/スレーブと同じです。切り替えてもすでに違いはありません。

  2. ホスト A のメモリ構成をアップグレードし、ホスト A を再起動して、次のチェックを実行します。

  • 4.1 新しいスレーブ Redis ログが異常かどうかを確認する

  • 4.2 info keyspace コマンドを使用して、新しいマスターと新しいスレーブに同じ数の db キーがあるかどうか、および異常なパスがないかどうかを確認します。

  • 4.3 新しいマスターにテストキーを書き込み、新しいスレーブで同期が成功するかどうかを確認します

  • 4.4 依存サーバのログに異常がないかを監視する

ここまで、上記の手順が正常に通過すれば、完璧なredisメモリアップグレード作業は完了です。

マスター/スレーブ切り替え後のデータ損失

その結果、ステップ 3 で、考えられなかった問題が発生しました。これは、マスター/スレーブ切り替え後の一部のデータの損失に直接つながり、新しいマスターはほぼ 1 年間読み取り専用状態になりました。 10分。

当時の状況はこんな感じでした。

手順3実行後、新しいスレーブredisのログを確認すると異常はありません しばらく様子を見てからホストAのアップグレードと再起動を検討中です APIの分単位の異常監視によりredisの小さな波が発生しました関連のアラーム。最初の反応は、新しいマスターと新しいスレーブで info キースペースを実行して、キーの数が一致していないかどうかを確認することです。マスター/スレーブのキーの数は一致していることがわかりますが、よく見てください。切り替え前のキーの総数は数百万個でした。切り替え前と比較すると、キーの総数は 100,000 レベルに減少し、キー データのほとんどが失われています。

新しいマスターと新しいスレーブのログを確認したところ、マスターとスレーブの切り替え後にデータの半分以上が失われる理由を説明できるログは見つかりませんでした。このとき、友人はメモリが足りないのではないかと初めて言及しました。 . その時は思いついてすぐに返信しました To: 新しいマスターのメモリがアップグレードされたばかりです コンテンツの拡張後にメモリが不足することはあり得ませんので、これは問題ではありません。

n分後...

友人は再び maxmemory の問題を提起し、すぐに要点を押さえ、ホスト B のメモリをアップグレードすれば、システム レベルでのメモリ不足の問題は発生しないとすぐに考えましたが、redis のメモリ使用量は実際には、maxmemory パラメータの影響を受けます。新しいマスターで config get maxmemory をすぐに実行します。わずか 3GB で、アップグレード前のデータによって使用される実際のメモリは 6GB を超えます。

新しいマスターの maxmemory パラメーターを直ちに増加すると、redis はすぐに通常の読み取りおよび書き込み可能な状態を復元し、redis 読み取り専用の大規模な波によって引き起こされるアラーム通知は急速に減少し始めました。

原因の場所

緊迫したエキサイティングなトラブルシューティングが終了しました。失われた主要データの回復作業が優先された後、失敗の詳細な理由を確認して整理し始めます。合計で次の質問があります。

  1. 先月、ホスト A と B の Redis が config set maxmemory によって 7GB に設定されたことをはっきりと覚えていますが、問題が発生したときに B の Redis の maxmemory 構成が 3GB になったのはなぜですか?

  2. ホスト B の maxmemory が 3GB の場合、マスターがスレーブとして動作するときに、マスターから 6GB を超えるデータを同期しても問題がないのはなぜですか? --マスター/スレーブ切り替えの前に、情報キースペースをチェックするか、マスターにテストキー同期チェックを書き込んでも問題ありません。

  3. マスター/スレーブ切り替え後にホスト B 上の鍵データが失われるのはなぜですか? これは、maxmemory 設定が小さすぎるためであり、これが失敗の直接の原因です。

  4. maxmemory パラメーターが制限を超え、一部のデータが削除されたために新しいマスターが読み取り専用状態になった後も、新しいマスターの実際のデータ サイズが依然として 3 GB を超えるのはなぜですか?

質問 3 を除いて、上記の 4 つの質問は明らかになりましたが、残りの 3 つの質問はすべて不可解です - 奇妙なものにはモンスターがいるはずです。

  1. 先月 redis maxmemory が変更されたとき、そのランタイム構成は config set コマンドによってのみ変更されましたが、対応する構成 redis.conf の maxmemory の値は変更されませんでした。ホスト B 上の Redis は、再起動後に redis.conf から redis をロードします.maxmemory、構成は正確に 3GB であり、maxmemory パラメーターは Redis ノードの独立した構成であり、スレーブはこの値をマスターから同期しません。

  2. redis5.0 バージョン以降、redis は新しいパラメータ recruit-ignore-maxmemory を導入しました。その公式ドキュメントは次のように定義されています。

Maxmemory on replicas
By default, a replica will ignore maxmemory (unless it is promoted to master after a failover or manually). It means that the eviction of keys will be handled by the master, sending the DEL commands to the replica as keys evict in the master side.
This behavior ensures that masters and replicas stay consistent, which is usually what you want. However, if your replica is writable, or you want the replica to have a different memory setting, and you are sure all the writes performed to the replica are idempotent, then you may change this default (but be sure to understand what you are doing).
Note that since the replica by default does not evict, it may end up using more memory than what is set via maxmemory (since there are certain buffers that may be larger on the replica, or data structures may sometimes take more memory and so forth). Make sure you monitor your replicas, and make sure they have enough memory to never hit a real out-of-memory condition before the master hits the configured maxmemory setting.
To change this behavior, you can allow a replica to not ignore the maxmemory. The configuration directives to use is:
replica-ignore-maxmemory no

一般的な考え方は、redis がスレーブとして使用される場合、マスターとスレーブのデータが常に一貫していることを保証するために、maxmemory パラメーターはデフォルトで無視されるということです。マスター/スレーブの実際のデータ サイズが maxmemory 設定より小さい場合、このパラメーターは効果がありません。今回のデータ損失の理由は、maxmemory (3GB) が実際のデータ サイズ (6GB+) よりも小さいためです。ホスト B がスレーブとして再起動されます。replica-ignore-maxmemory がデフォルトでオンになっていて、スレーブである場合に maxmemory の制限を無視する場合、および Sentinel フェイルオーバー マスター名が実行されてホスト B を新しいマスターに切り替える場合、新しいマスターは、replica-ignore-maxmemory の影響を受けず、自身の maxmemory<actual データ サイズを超えると、キーが積極的に直接削除され、データ損失が発生します。

  1. ホスト B がマスターとして削除キー戦略を実行し、最終的に読み取り専用状態になった後も、ホスト B の実際のデータ サイズが依然として 3 GB を超える理由については、オンライン Redis 構成戦略が volatile-lru であるためです。有効期限が切れた時間のみを削除する戦略。有効期限が切れていないキーの場合、キーは削除されません。

要約する

一般に、この失敗の根本原因は、Redis の構成と操作における私の経験不足にありますが、ランタイム maxmemory を調整するときに次のいずれかを達成できれば、この失敗は発生しません。

  1. ランタイム maxmemory を調整するときは、構成ファイル maxmemory を調整して一貫性を保ちます。

  2. 構成ファイル maxmemory を 0 に設定します -- メモリ使用量が無制限になることを意味します。

redis の知識と経験が不足していたからこそ、実行時設定と静的設定の不一致によって引き起こされる問題について考えていなかったので、今回は必然的に落とし穴を踏むことになります。

おすすめ

転載: blog.csdn.net/m0_37723088/article/details/130998161