Redis グラフィック ガイド

1.Redisとは何ですか?

Redis (REmote DIctionary Service) は、オープンソースのキーと値のデータベース サーバーです。

Redis は、より正確にはデータ構造サーバーとして説明されます。Redis のこの特別な特性により、Redis は開発者の間で人気があります。

Redis は反復や並べ替えによってデータを処理するのではなく、最初からデータ構造に従ってデータを整理します。初期の頃は、Memcached と同じように使用されていましたが、Redis が改良されるにつれて、パブリッシュ/サブスクライブ メカニズム、ストリーミング、キューなど、他の多くのユースケースでも使用できるようになりました。

基本的に、Redis は、アプリケーションのパフォーマンスの向上に役立つ、別の「実際の」データベース (MySQL や PostgreSQL など) の前のキャッシュとして使用されるメモリ内データベースです。次のような高いメモリ アクセス速度を利用して、コア アプリケーション データベースの負荷を軽減します。

  • 変更頻度は低く、頻繁に要求されるデータ

  • ミッションクリティカル性が低く、頻繁に変更されるデータ

上記のデータの例には、セッションまたはデータのキャッシュのほか、リーダーボードやダッシュボードの集約分析が含まれる場合があります。

ただし、多くのユースケース シナリオでは、Redis は本格的なプライマリ データベースとして使用できる十分な保証を提供します。Redis プラグインとそのさまざまな高可用性 (HA) 設定と組み合わせると、データベースとしての Redis は特定のシナリオやワークロードに非常に役立ちます。

もう 1 つの重要な側面は、Redis ではキャッシュとデータ ストレージの間の境界があいまいになっていることです。ここで理解しておくべき重要な点は、ストレージに SSD または HDD を使用する従来のデータベースよりも、メモリ内のデータの読み取りと操作がはるかに高速であるということです。

当初、Redis は Memcached と比較されることが多かったのですが、当時、Memcached には不揮発性の永続性がありませんでした。

2 つのキャッシュ間の現在の機能の内訳は次のとおりです。

現在、データをディスクに永続化する構成方法は複数ありますが、永続性が最初に導入されたとき、Redis はスナップショットを使用して、メモリ内のデータを非同期にコピーすることで永続性を実現していました。残念ながら、このメカニズムの欠点は、スナップショット間でデータが失われる可能性があることです。

Redis は 2009 年の設立以来、非常に成熟しました。Redis をデータ ストレージ システムの武器庫に追加できるように、そのアーキテクチャとトポロジのほとんどを説明します。

2. Redis アーキテクチャ

Redis の内部について説明する前に、さまざまな Redis のデプロイメントとそのトレードオフについて説明しましょう。

主に次の設定に焦点を当てます。

  • 単一の Redis インスタンス

  • Redis の高可用性

  • レディスセンチネル

  • Redis クラスター

ユースケースと規模に基づいて、どの設定を使用するかを決定します。

単一の Redis インスタンス

単一の Redis インスタンスは、Redis をデプロイする最も簡単な方法です。これにより、ユーザーは小規模なインスタンスをセットアップして実行できるようになり、サービスの迅速な成長と加速に役立ちます。ただし、この展開には欠点がないわけではありません。たとえば、このインスタンスに障害が発生するか使用できなくなると、クライアントによる Redis への呼び出しはすべて失敗し、システム全体のパフォーマンスと速度が低下します。

十分なメモリとサーバー リソースがあれば、このインスタンスは非常に強力になります。主にキャッシュに使用されるシナリオでは、最小限のセットアップでパフォーマンスが大幅に向上する可能性があります。十分なシステム リソースがあれば、アプリケーションが実行されているのと同じマシンにこの Redis サービスをデプロイできます。

システム内のデータを管理する場合、Redis のいくつかの概念を理解することが不可欠です。Redis に送信されたコマンドは、まずメモリ内で処理されます。次に、これらのインスタンスに永続性が設定されている場合、一定の間隔でデータ永続 RDB (Redis データの非常にコンパクトなポイントインタイム表現) スナップショットまたは AOF (追加専用ファイル) を生成するフォーク プロセスが行われます。 。

これら 2 つのプロセスにより、Redis は長期ストレージを保持し、さまざまなレプリケーション戦略をサポートし、より複雑なトポロジを可能にすることができます。Redis がデータを永続化するように設定されていない場合、再起動またはフェイルオーバー時にデータが失われます。再起動時に永続性が有効になっている場合、RDB スナップショットまたは AOF からすべてのデータがメモリにロードされ、インスタンスは新しいクライアント リクエストをサポートできるようになります。

そうは言っても、使用できる分散型 Redis セットアップをいくつか見てみましょう。

Redis の高可用性

Redis のもう 1 つの一般的な設定は、マスター/スレーブ デプロイメント モードです。このモードでは、スレーブ デプロイメントがマスター デプロイメントとのデータ同期を維持します。データがマスター インスタンスに書き込まれると、これらのコマンドのコピーがスレーブ デプロイメント クライアントの出力バッファに送信され、データの同期が行われます。デプロイメントには 1 つ以上のインスタンスが存在する可能性があります。これらのインスタンスは、Redis 読み取り操作を拡張したり、メインが失われた場合にフェイルオーバーを提供したりするのに役立ちます。

現在、分散システムに入っているため、このトポロジーでは新たに考慮すべきことがたくさんあります。以前は単純だったものが、今では複雑になっています。

Redis レプリケーション

Redis の各マスター インスタンスには、レプリケーション ID とオフセットがあります。これら 2 つのデータは、レプリカがレプリケーション プロセスを続行できる時点、または完全同期を実行する必要があるかどうかを判断するために重要です。このオフセットは、メインの Redis デプロイメントで発生する操作ごとに増分されます。

具体的には、Redis レプリカ インスタンスがプライマリ インスタンスからわずか数オフセットだけ離れている場合、プライマリ インスタンスから残りのコマンドを受信し、同期が完了するまでデータ セット上でそれらのコマンドを再生します。2 つのインスタンスがレプリケーション ID に同意できない場合、またはプライマリ インスタンスがオフセットを知らない場合、レプリカは完全な同期を要求します。この時点で、マスター インスタンスは新しい RDB スナップショットを作成し、レプリカに送信します。

この転送の間に、マスター インスタンスはスナップショットの有効期限と現在のオフセットの間のすべての中間更新命令をバッファリングし、スナップショットが同期された後にそれらの命令がレプリカ インスタンスに送信されるようにします。これが完了すると、コピーは通常どおり続行できます。

インスタンスのレプリケーション ID とオフセットが同じであれば、それらのデータはまったく同じになります。なぜ ID をコピーする必要があるのか​​疑問に思われるかもしれません。Redis インスタンスがマスターに昇格されるか、マスターとして最初から再起動されると、新しいレプリケーション ID が与えられます。

これは、この新しく昇格されたレプリカ インスタンスがどの以前のマスター インスタンスからレプリケートされたかを推測するために使用されます。これにより、新しいマスターが古いレプリケーション ID を記憶しているため、部分的な同期 (他のレプリカ ノードと) を実行できるようになります。

たとえば、2 つのインスタンス (マスターとスレーブ) は同じレプリケーション ID を持っていますが、オフセットはコマンド数百個分異なります。つまり、これらのオフセットに続くコマンドがインスタンス上で再生されると、それらのインスタンスは同じデータセットを持つことになります。ここで、レプリケーション ID が完全に異なり、新しく降格された (または再結合された) スレーブ ノードの前のレプリケーション ID がわからない場合 (共通の祖先がない場合) です。コストのかかる完全同期を実行する必要があります。

対照的に、以前のレプリケーション ID がわかっている場合は、それらが共有する共通の祖先を推測できるため、データを同期させる方法を推測でき、部分同期にはオフセットが再び意味を持ちます。

レディスセンチネル

Sentinel は分散システムです。すべての分散システムと同様に、Sentinel にはいくつかの利点と欠点があります。Sentinel は、Sentinel プロセスのグループが連携して状態を調整し、Redis に高可用性を提供するように設計されています。結局のところ、障害から保護するシステムに独自の単一障害点が存在することは望ましくありません。

Sentinel はいくつかのことを処理します。まず、現在のマスター インスタンスとスレーブ インスタンスが適切に機能し、応答していることを確認します。これは、マスター ノードやスレーブ ノードが失われた場合に Sentinel (他の Sentinel プロセスとともに) が警告を発してアクションを実行できるようにするために必要です。2 番目に、他のシステムの Zookeeper や Consul と同様に、サービス検出の役割を果たします。したがって、新しいクライアントが Redis に書き込もうとすると、Sentinel は現在のプライマリ インスタンスが何であるかをクライアントに伝えます。

そのため、Sentinel は可用性を常に監視し、その情報をクライアントに送信して、クライアントがフェイルオーバー時に対応できるようにします。

その責任は次のとおりです。

  • モニタリング - マスター インスタンスとスレーブ インスタンスが期待どおりに動作していることを確認します。

  • 通知 - Redis インスタンスのイベントをシステム管理者に通知します。

  • フェイルオーバー管理 - プライマリ インスタンスが利用できなくなり、十分な (クォーラム) ノードがこれが正しいと同意した場合、Sentinel ノードはフェイルオーバーを開始できます。

  • 構成管理 - Sentinel ノードは、現在のマスター Redis インスタンスの検出サービスとしても機能します。

この方法で Redis Sentinel を使用すると、障害を検出できます。この検出には、現在のマスター インスタンスが使用できなくなったことに同意する複数のセンチネル プロセスが含まれます。この合意プロセスはクォーラムと呼ばれます。これにより堅牢性が向上し、1 台のマシンが誤動作してマスター Redis ノードにアクセスできなくなるのを防ぎます。

この設定には欠点がないわけではないため、Redis Sentinel を使用する場合の推奨事項とベスト プラクティスについていくつか説明します。

Redis Sentinel はさまざまな方法でデプロイできます。正直なところ、賢明な提案をするには、システムに関する背景情報がさらに必要です。一般的なガイドとして、センチネル ノードと実際に Redis を使用するクライアントとの間のネットワーク到達可能性の違いを考慮する必要がないように、(可能であれば) 各アプリケーション サーバーの隣でセンチネル ノードを実行することをお勧めします。

Sentinel は Redis インスタンスまたはスタンドアロン ノードで実行できますが、処理が異なるため、作業がより複雑になります。少なくとも 3 つのノードを実行し、少なくとも 2 つのクォーラムを持つことをお勧めします。以下は、クラスター内のサーバーの数と、それに関連するクォーラム、および許容できる持続可能な障害を内訳した簡単なグラフです。

これはシステムによって異なりますが、一般的な考え方は同じです。

このような設定で何が問題となるのかを少し考えてみましょう。このシステムを十分に長く実行すると、これらすべてに遭遇することになります。

  1. センチネル ノードの定足数がある場合はどうなるでしょうか?

  2. ネットワークの分割によって古いマスター インスタンスが少数派になったらどうなるでしょうか? これらの書き込みはどうなりますか? (ネタバレ: システムが完全に復元されると、それらは失われます)

  3. センチネル ノードとクライアント ノード (アプリケーション ノード) のネットワーク トポロジがずれているとどうなりますか?

特にディスクへの永続化操作 (以下を参照) は非同期であるため、耐久性の保証はありません。また、クライアントが新しいプライマリを発見したときに、未知のプライマリへの書き込みでどれだけ損失が生じるかという厄介な質問もあります。Redis では、新しい接続を確立するときに新しいマスターにクエリを実行することをお勧めします。システム構成によっては、これは重大なデータ損失を意味する可能性があります。

プライマリ インスタンスが少なくとも 1 つのレプリカ インスタンスに書き込みをレプリケートするように強制する場合、損傷の範囲を軽減する方法がいくつかあります。すべての Redis レプリケーションは非同期であるため、トレードオフがあることに注意してください。したがって、承認を個別に追跡する必要があり、少なくとも 1 つのレプリカ インスタンスが承認を受け取らない場合、マスター インスタンスは書き込みの受け入れを停止します。

Redis クラスター

すべてのデータを 1 台のマシンのメモリに保存できなくなったらどうなるのか、疑問に思ったことがある方も多いと思います。現在、単一サーバーで利用可能な最大 RAM は 24TIB であり、これは現在 AWS によってオンラインでリストされています。確かに、これは多量ですが、一部のシステムでは、たとえキャッシュ層であっても十分ではありません。

Redis Cluster を使用すると、Redis の水平拡張が可能になります。

まず、いくつかの用語の説明を省略します。Redis Cluster を使用することに決めた後、保存するデータを複数のマシンに分散させることにしました。これはシャーディングと呼ばれます。したがって、クラスター内の各 Redis インスタンスはデータ全体のシャードとみなされます。

これにより、新たな問題が生じます。キーをクラスターにプッシュした場合、どの Redis インスタンス (シャード) がデータを保持しているかをどのように確認すればよいでしょうか? これを行うにはいくつかの方法がありますが、Redis Cluster はアルゴリズム シャーディングを使用します。

特定のキーのシャードを見つけるには、シャードの合計数を法としてキーをハッシュします。次に、特定のキーが常に同じシャードにマップされることを意味する決定論的ハッシュ関数を使用して、特定のキーの将来の読み取りがどこで行われるかを推測できます。

後で新しいシャードをシステムに追加したい場合はどうなりますか? このプロセスはリシャーディングと呼ばれます。

キー「foo」が以前にシャード 0 にマッピングされていたとします。新しいシャードが導入された後は、シャード 5 にマッピングされる可能性があります。ただし、システムを迅速に拡張する必要がある場合、新しいシャード マッピングに到達するためにデータを移動するのは遅く、非現実的です。また、Redis クラスターの可用性にも悪影響を及ぼします。

Redis Cluster は、ハッシュスロットと呼ばれるこの問題の解決策を設計し、すべてのデータがそれにマップされます。16K のハッシュ スロットがあります。これにより、クラスター全体にデータを分散する合理的な方法が得られ、新しいシャードを追加するときにシステム間でハッシュ スロットを移動するだけです。これにより、ハッシュロットをあるシャードから別のシャードに移動するだけで済み、新しいマスター インスタンスをクラスターに追加するプロセスが簡素化されます。

これはダウンタイムなしで実現でき、パフォーマンスへの影響も最小限に抑えられます。例を挙げて説明しましょう。

  • M1 には 0 ~ 8191 のハッシュ スロットが含まれます。

  • M2 には、8192 から 16383 までのハッシュ スロットが含まれます。

したがって、「foo」をマップするには、キー (foo) の決定論的ハッシュを取得し、ハッシュ スロットの数 (16K) でそれを変更し、結果として M2 のマップが得られます。ここで、新しいインスタンス M3 を追加するとします。新しいマッピングは次のようになります。

  • M1 には 0 ~ 5460 のハッシュ スロットが含まれます。

  • M2 には、5461 ~ 10922 のハッシュ スロットが含まれます。

  • M3 には、10923 から 16383 までのハッシュ スロットが含まれます。

M1 のハッシュ スロットをマップし、現在 M2 にマップされているすべてのキーを移動する必要があります。ただし、ハッシュ スロットの個々のキーのハッシュは、すでにハッシュ スロットに分割されているため、移動する必要はありません。したがって、このレベルのミスディレクションは、アルゴリズムシャーディングのリシャーディング問題を解決します。

うわさ話のプロトコル

Redis クラスターは、ゴシップを使用してクラスター全体の健全性を判断します。上の図では、3 つの M ノードと 3 つの S ノードがあります。これらすべてのノードは常に通信を行って、どのシャードが利用可能でリクエストを処理する準備ができているかを把握します。

十分な数のシャードが M1 が応答しないことに同意した場合、クラスターを正常に保つために M1 のレプリカ S1 をマスターに昇格させることを決定できます。この操作をトリガーするために必要なノードの数は構成可能であり、正しく実行する必要があります。間違って実行すると、パーティションの両側が等しいときに結合を解除できず、クラスタが分割される可能性があります。この現象はスプリットブレインと呼ばれます。一般に、最も堅牢なセットアップを実現するには、奇数のマスターと 2 つのレプリカが必要です。

3. Redis 永続モデル

Redis を使用してあらゆる種類のデータを保存し、安全な保存が必要な場合は、Redis がどのようにこれを行うかを理解することが重要です。多くのユースケースでは、Redis に保存されているデータが失われたとしても、それは世界の終わりではありません。キャッシュとして、またはリアルタイム分析をサポートする場所として使用します。データ損失が発生しても世界の終わりではありません。

他のシナリオでは、データの耐久性と回復に関して何らかの保証が必要になります。

持続性なし

永続性なし: 必要に応じて、永続性を完全に無効にすることができます。これは Redis を実行する最速の方法ですが、耐久性の保証はありません。

RDBファイル

RDB (Redis データベース): RDB 永続化は、指定された間隔でデータ セットのポイントインタイム スナップショットを実行します。

このメカニズムの主な欠点は、スナップショット間でデータが失われることです。さらに、このストレージ メカニズムはメイン プロセスのフォークにも依存しているため、より大きなデータ セットでのリクエストの処理に一時的な遅延が発生する可能性があります。そうは言っても、RDB ファイルは AOF よりもはるかに高速にメモリにロードされます。

AOF

AOF (追加専用ファイル): AOF は、サーバーが受信したすべての書き込み操作を永続的に記録します。これらの操作は、サーバーが元のデータ セットの再構築を開始するときに再度実行されます。

この永続化方法は追加専用のファイルであるため、RDB スナップショットよりも耐久性が高くなります。操作が発生すると、それらはログにバッファリングされますが、まだ永続化されていません。このログは実際に実行したコマンドと一致しているため、必要に応じて再生できます。

次に、可能であれば (この実行が構成可能な場合) fsync を使用してディスクにフラッシュし、永続化します。欠点は、形式がコンパクトではなく、RDB ファイルよりも多くのディスクを使用することです。

なぜ両方も持たないのでしょうか?

RDB + AOF: AOF と RDB を同じ Redis インスタンス内で組み合わせることができます。言うなれば、取引速度と持続性は妥協です。これは Redis をセットアップする許容可能な方法だと思います。再起動の場合、両方が有効になっている場合、Redis は最も完全な AOF を使用してデータを再構築することに注意してください。

分岐

永続性の種類を理解したところで、Redis のようなシングルスレッド アプリケーションで永続性を実際に実装する方法について説明します。

私の意見では、Redis の最も優れた点は、フォークとコピーオンライトを活用してデータの永続化を効率的に促進する方法です。

フォークとは、オペレーティング システムが自身のコピーを作成することで新しいプロセスを作成する方法です。このようにして、新しいプロセス ID およびその他の情報とハンドルを取得し、新しくフォークされたプロセス (子プロセス) が元のプロセスの親プロセスと通信できるようにします。

さて、事態は面白くなってきました。Redis は大量のメモリを割り当てるプロセスですが、どうすればメモリ不足にならずにコピーできるのでしょうか?

プロセスをフォークすると、親プロセスと子プロセスがメモリを共有し、Redis は子プロセスでスナップショット (Redis) プロセスを開始します。これは、フォークの作成時にメモリへの参照を渡す、コピーオンライトと呼ばれるメモリ共有手法によって実現されます。子プロセスがディスクに保存されている間に変更が発生しなかった場合、新しい割り当ては行われません。

変更が発生した場合、カーネルは各ページへの参照を追跡し、ページに複数の変更がある場合、変更は新しいページに書き込まれます。子プロセスは変更をまったく認識せず、一貫したメモリ スナップショットを保持します。その結果、メモリのごく一部のみを使用しながら、潜在的なギガバイトのメモリの特定時点のスナップショットを非常に迅速かつ効率的に取得できるようになりました。

おすすめ

転載: blog.csdn.net/LinkSLA/article/details/132595570