Redis Clusterのデータスライスメカニズム


前回の「分布式データキャッシュにおける一致性ハッシュアルゴリズム」では、一致性ハッシュアルゴリズムの基本原理と実現について述べたが、今日はRedis Clusterを例に、分布式データキャッシュにおけるデータスライス、オンラインオフライン時のデータ移行、リダイレクト要求などの操作について詳しく説明する.

Redisクラスタの概要


Redis ClusterはRedisの分散ソリューションであり、3.0リリースで正式にリリースされ、Redisの分散に関するニーズを効果的に解決しました.
Redis Clusterは一般的に複数のノードから構成され、ノード数は少なくとも6つであり、3つがプライマリノードであり、3つがセカンダリノードであることを保証することができる.3つのプライマリノードはスロットを割り当て、クライアントのコマンド要求を処理し、セカンダリノードはプライマリノードの障害後にプライマリノードの代わりに使用できます.
画像ソースredislabs
上の図に示すように、このクラスタには6個のRedisノードが含まれ、3マスタ3スレーブは、それぞれM 1,M 2,M 3,S 1,S 2,S 3である.プライマリがRedisノード間からデータコピーを行うほか,すべてのRedisノード間でGossipプロトコルを用いて通信を行い,メンテナンスノードメタデータ情報を交換する.
一般に、プライマリRedisノードはClientsの読み書き操作を処理し、スレーブノードは読み書き操作のみを処理する.

データスライスポリシー


分散型データストレージ方式において最も重要な点は、データスライス、いわゆるShardingである。

クラスタが水平に拡張できるようにするために、最も重要な問題は、データセット全体を一定の規則に従って複数のノードに割り当てる方法であり、一般的なデータスライスの方法は、範囲スライス、ハッシュスライス、コンシステンシハッシュアルゴリズム、ハッシュスロットなどである.
範囲スライスは、データセットが秩序化されていると仮定し、順序が近いデータを一緒に配置し、遍歴操作をよくサポートすることができる.範囲スライスの欠点は、順番に書くときにホットスポットがあることです.たとえば、ログ・タイプの書き込みでは、一般的にログの順序は時間に関連しており、時間は単調に増加するため、書き込みのホットスポットは常に最後のスライスになります.
リレーショナル・データベースでは、テーブル・スキャンまたはインデックス・スキャンが頻繁に必要なため、基本的には範囲のスライス・ポリシーが使用されます.
ハッシュスライスとコンシステンシハッシュアルゴリズムは前の文章で勉強しましたが、興味のある学生は「分散データキャッシュにおけるコンシステンシハッシュアルゴリズム」を理解することができます.次に,Redisの仮想ハッシュスロット戦略を主に見た.
Redis Clusterは仮想ハッシュスロットパーティションを採用し、すべてのキーはハッシュ関数に基づいて0~16383整数スロット内にマッピングされ、計算式:slot=CRC 16(key)&16383.各ノードは、スロットの一部と、スロットにマッピングされたキー値データの維持を担当します.
Redis仮想スロットパーティションの特徴:
  • データとノードの関係をデカップリングし、ノードの拡張と収縮の難易度を簡素化した.
  • ノード自身のメンテナンススロットのマッピング関係は、クライアントまたはエージェントサービスメンテナンススロットパーティションメタデータ
  • を必要としない.
  • は、ノード、スロット、キー間のマッピングクエリーをサポートし、データルーティング、オンラインクラスタ伸縮などのシーンに使用します.

  • Redisクラスタは、柔軟なノード拡張および縮小スキームを提供する.クラスタ対外サービスに影響を及ぼさない場合、クラスタにノードを追加して拡張してもよいし、一部のノードをオフラインで縮小してもよい.スロットはRedisクラスタ管理データの基本単位であり,クラスタ伸縮はスロットとデータのノード間の移動であるといえる.
    まずRedisクラスタ伸縮の原理を見てみましょう.次に、Redisノードのデータ移行中または障害復旧時にクラスタが使用可能であることを保証する方法について説明します.

    かくさんクラスタ


    オンラインノードの拡張操作を読者によりよく理解させるために,Redis Clusterの命令によりプロセス全体をシミュレートした.
    Redisの新しいノードが実行され、既存のクラスタに追加されると、スロットとデータを移行する必要があります.まず、新しいノードにスロットの移行計画を指定し、移行後に各ノードが類似数のスロットを担当することを確認し、これらのノードのデータが均一であることを保証します.
    1)まずRedisノードを起動し,M 4と記す.2)cluster meetコマンドを使用して、新しいRedisノードをクラスタに追加します.新しいノードは最初はプライマリノード状態であり、担当するスロットがないため、読み書き操作を受け入れることができません.その後、スロットを移行し、データを埋め込みます.3)M 4ノードにcluster setslot{slot}importing{sourceNodeId}コマンドを送信し,ターゲットノードにスロットのデータをインポートする準備をさせる.4)ソースノード,すなわちM 1,M 2,M 3ノードに対してcluster setslot{slot}migrating{targetNodeId}コマンドを送信し,ソースノードにスロットのデータを準備させる.5)ソースノードはcluster getkeysinslot{slot}{count}コマンドを実行し、count個のスロット{slot}に属するキーを取得し、ステップ6の操作を実行してキー値データを移行する.6)ソースノード上でmigrate{targetNodeIp}""0{timeout}keys{key...}コマンドは、取得したキーをpipelineメカニズムでターゲットノードに一括移行し、一括移行バージョンのmigrateコマンドはRedis 3.0.6以上で提供されます.7)スロット内のすべてのキー値データがターゲットノードに移行するまで、手順5と手順6を繰り返します.8)クラスタ内のすべてのプライマリノードにcluster setslot{slot}node{targetNodeId}コマンドを送信し、スロットがターゲットノードに割り当てられることを通知する.スロットノードマッピングの変更がタイムリーに伝播することを保証するためには、移行されたスロット実行の新しいノードを更新するために、すべてのプライマリノードに送信する必要がある.

    しゅうしゅくクラスタ


    縮小ノードはRedisノードをオフラインにし、プロセス全体に次のような操作フローが必要です.
    1)まず,ラインオフノードに責任あるスロットがあるかどうかを確認し,もしそうであれば,スロットを他のノードに移行し,ノードラインオフ後のクラスタスロットノード全体のマッピングの完全性を保証する必要がある.2)下線ノードがスロットを担当しなくなったり,それ自体がスレーブノードであったりした場合,クラスタ内の他のノードに下線ノードを忘れたことを通知することができ,すべてのノードがノードを変更し忘れた後に正常に閉じることができる.
    下線ノードは,ノード自身が担当するスロットを他のノードに移行する必要があり,原理は以前のノード拡張の移行スロットプロセスと一致する.
    スロットの移行が完了すると、クラスタ内のすべてのノードにオフラインを忘れたノードを通知する必要があります.つまり、他のノードがオフラインするノードとGossipメッセージ交換を行わないようにする必要があります.
    Redisクラスタはcluster forget{downNodeId}コマンドを使用して指定したノードを無効リストに追加し、無効リスト内のノードはGossipメッセージを送信しません.

    クライアントルーティング


    クラスタモードでは、Redisノードが任意のキー関連コマンドを受信すると、まずキー対応のスロットを計算し、スロットに基づいて対応するノードを探し出し、ノードが自身であればキーコマンドを処理する.そうでなければ、MOVEDリダイレクトエラーに返信し、クライアントに正しいノードを要求することを通知します.このプロセスをMOVEDリダイレクトと呼ぶ.
    なお、Redis計算スロットの場合はキー値の内容のみを単純に計算するのではなく、キー値の内容が括弧を含む場合は括弧内の内容のみを計算する.たとえばkeyがuser:{10000}:booksの場合、ハッシュ値を計算すると10000しか計算されません.
    MOVEDエラーの例としては、キーxが属するハッシュスロット3999と、このスロットの処理を担当するノードのIPおよびポート番号127.0.0.1:6381がある.クライアントは,このIPとポート番号に基づいて,GETコマンド要求を所属ノードに再送する必要がある.
    GET x
    -MOVED 3999 127.0.0.1:6381

    リダイレクトを要求するとIOオーバーヘッドが増加するため、Redisクラスタの効率的な使用ではなく、Smartクラスタクライアントを使用します.SmartクライアントはslotからRedisノードへのマッピング関係を内部で維持することで、ローカルでキーからノードへの検索を実現することができ、IO効率の最大化を保証し、MOVEDリダイレクトはクライアントのマッピング関係の更新を支援する.
    Redisクラスタは、水平伸縮を完了するためにオンライン移行スロット(slot)とデータをサポートします.slotに対応するデータがソースノードからターゲットノードへ移行する過程で、クライアントはインテリジェントな移行を行う必要があり、キーコマンドが正常に実行されることを保証します.たとえば、slotデータがソースノードからターゲットノードに移行すると、ソースノードにデータの一部が、ターゲットノードにデータの一部が表示されます.
    したがって、上記の状況を総合すると、クライアントコマンド実行フローは以下のようになる.
  • クライアントは、ローカルslotキャッシュに従ってソースノードにコマンドを送信し、キーが存在する場合は直接実行し、結果をクライアントに返す.
  • ノードがMOVEDエラーを返すと、ローカルのslotからRedisノードへのマッピング関係が更新され、要求が再開始される.
  • データが移行中の場合、ノードはASKリダイレクト異常に返信します.フォーマットは以下の通りです:(error)ASK{slot}{targetIP}:{targetPort}
  • クライアントは、ASKリダイレクト異常からターゲットノード情報を抽出し、askingコマンドを送信してターゲットノードにクライアント接続IDを開き、キーコマンドを実行する.

  • ASKとMOVEDはいずれもクライアントへのリダイレクト制御であるが,本質的な違いがある.ASKリダイレクトはクラスタがslotデータの移行を行っていることを示し、クライアントはいつ移行が完了するか分からないため、一時的なリダイレクトのみであり、クライアントはslotからRedisノードへのマッピングキャッシュを更新しない.しかし、MOVEDリダイレクトは、キーに対応するスロットが新しいノードに明確に指定されているため、slotからRedisノードへのマッピングキャッシュを更新する必要があることを示している.

    フェイルオーバ


    Redisクラスタ内の少数のノードに障害が発生した場合、自動フェイルオーバによってクラスタが正常に外部にサービスを提供できることを保証します.
    Redisノードが客観的にダウンラインされると、Redisクラスタはノードから選択されたマスターによって代替ノードを選択し、クラスタの高可用性を保証します.この内容は本文の核心内容ではなく、興味のある学生は自分で勉強することができます.
    でも、ちょっと注意が必要です.デフォルトでは、クラスタ16384スロットのいずれかがノードに割り当てられていない場合、クラスタ全体は使用できません.任意のキーコマンドを実行してCLUSTERDOWN Hash slot not servedコマンドに戻ります.スロットを持つプライマリノードがオフラインになると、障害発見から自動完了への移行中にクラスタ全体が使用不可になり、ほとんどのビジネスではこれに耐えられないため、パラメータcluster-require-full-coverageをnoに構成することをお勧めします.プライマリノードが障害した場合、スロットを担当する関連コマンドの実行にのみ影響し、他のプライマリノードの可用性には影響しません.

    リファレンス

  • 「Redis開発と運営」
  • https://juejin.im/entry/593a4...
  • https://phachon.com/redis/red...
  • http://kdf5000.com/2017/04/17...