この記事では、Redis クラスターの仕様の詳細な説明を中心に、ノード障害検出、クラスター状態検出、スレーブ ノード選出などの Redis クラスターの機能について、最も基本的なことから説明します。より詳しく書かれていますので、必要な方は参考にしていただければ幸いです。
はじめに
このドキュメントは、開発中の Redis クラスター機能の仕様ドキュメントです。このドキュメントは 2 つの部分に分かれています:
最初の部分では、不安定版ブランチに実装されている機能を紹介します。
2 番目の部分では、まだ実装されていない機能を紹介します。
クラスタ機能の設計変更に伴いドキュメント各部の内容が変更される可能性がありますが、その中でも未実装の機能は実装済みの機能よりも変更される可能性が高くなります。
この仕様には、クライアント ライブラリを作成するために知っておく必要があるすべてが含まれていますが、ここにリストされている詳細の一部は将来変更される可能性があることに注意してください。
Redis クラスターとは何ですか?
Redis クラスターは、分散型のフォールトトレラントな Redis 実装です。クラスターが使用できる機能は、通常のスタンドアロン Redis が使用できる機能のサブセットです。
Redis クラスターにはセントラル ノードやプロキシ ノードはありません。クラスターの主な設計目標の 1 つは、線形スケーラビリティを実現することです。
Redis クラスターは、一貫性を確保するために、ある程度のフォールト トレランスを犠牲にします。システムは、ネットワーク切断 (ネット スプリット) やノード障害 (ノード障害) に対する限定的な耐性を確保するために最善を尽くし、可能な限りデータの一貫性を維持します。
クラスターは、ノード障害をネットワーク切断の特殊なケースの 1 つとして扱います。
クラスターのフォールトトレランス機能は、マスターノード(master)とスレーブノード(slave)の2つの役割を持つノードを使用することで実現されます。
マスターノードとスレーブノードは、まったく同じサーバー、その機能を使用して実装されます。まったく同じですが、スレーブ ノードは通常、障害が発生したマスター ノードを置き換えるためにのみ使用されます。
ただし、「最初に書き込み、後で読み取る」操作の一貫性 (書き込み後の読み取りの一貫性) を保証する必要がない場合は、スレーブ ノードを使用して読み取り専用クエリを実行できます。
Redis クラスターによって実装される機能のサブセット
Redis クラスターは、スタンドアロン Redis で単一のデータベース キーを処理するすべてのコマンドを実装します。
集合の和集合演算やコレクション演算など、複数のデータベースキーに対する複雑な計算演算は実装されておらず、理論的に複数のノードから複数のデータベースキーを使用する必要があるコマンドも実装されていません。
将来的には、ユーザーは MIGRATE COPY コマンドを使用して、クラスターの計算ノード内の複数のデータベース キーに対して読み取り専用操作を実行できるようになる可能性がありますが、クラスター自体は、複数のデータベース キーを必要とする操作を実装しません。 be 複数のノードを移動するための複雑なマルチキー コマンド。
Redis クラスターは、スタンドアロン Redis のような複数のデータベース機能をサポートしていません。クラスターはデフォルトのデータベース 0 のみを使用し、SELECT コマンドを使用できません。
Redis クラスター プロトコルのクライアントとサーバー
Redis クラスター内のノードには次の役割があります:
キーと値のペアのデータを保持します。
正しいノードへのキーのマッピングなど、クラスターのステータスを記録します。
他のノードを自動的に検出し、適切に動作していないノードを特定し、必要に応じてスレーブ ノードから新しいマスター ノードを選択します。
上記のタスクを実行するために、クラスター内の各ノードは他のノードとの「クラスター バス」を確立します。この接続は TCP 接続であり、通信にバイナリ プロトコルを使用します。
Gossip プロトコルは、次のタスクを実行するためにノード間で使用されます:
クラスターに関する情報を伝播して、新しいノードを検出します。
他のノードにPINGパケットを送信し、対象ノードが正常に動作しているか確認します。
特定のイベントが発生したときにクラスター情報を送信します。
さらに、クラスター接続は、クラスター内の情報を公開またはサブスクライブするためにも使用されます。
クラスターノードはコマンドリクエストをプロキシできないため、ノードが-MOVEDまたは-ASKリダイレクトエラーを返した場合、クライアントはコマンドリクエストを自ら他のノードに転送する必要があります。
クライアントはクラスター内の任意のノードにコマンドリクエストを自由に送信でき、必要に応じてステアリングエラーによって提供される情報に基づいてコマンドを正しいノードに転送できるため、理論上、クライアントは次のようになります。クラスターのステータス情報を保存する必要はありません。
ただし、クライアントがキーとノード間のマッピング情報を保存できれば、考えられるリダイレクトの数を効果的に減らすことができ、それによってコマンド実行の効率が向上します。
キー配布モデル
Redis クラスターのキー空間は 16384 個のスロットに分割されており、クラスター内の最大ノード数も 16384 です。
推奨される最大ノード数は約 1,000 です。
各マスターノードは、16384 のハッシュ スロットの一部の処理を担当します。
クラスターが「安定した」状態にあるというときは、クラスターが再構成操作を実行しておらず、各ハッシュ スロットが 1 つのノードのみによって処理されていることを意味します。
再構成とは、特定のスロットをあるノードから別のノードに移動することを指します。
マスター ノードは任意の数のスレーブ ノードを持つことができます。これらのスレーブ ノードは、ネットワークが切断された場合やノードに障害が発生した場合にマスター ノードを置き換えるために使用されます。
以下は、キーをスロットにマッピングするアルゴリズムです:
HASH_SLOT = CRC16(key) mod 16384
以下は、アルゴリズムで使用されるパラメータです:
アルゴリズムの名前: XMODEM (ZMODEM またはとしても知られています) CRC-16/ACORN)
結果の長さ: 16 ビット
ポリ: 1021 (つまり、x16 + x12 + x5 + 1)
初期値: 0000
入力バイトを反映: False
出力 CRC を出力 (出力 CRC を反映) ): False
Xor CRC を出力する定数、CRC 出力値: 0000
入力「123456789」に対するこのアルゴリズムの出力: 31C3
付録 A には、使用される CRC16 アルゴリズムの実装でクラスター情報が示されています。
CRC16 アルゴリズムによって生成された 16 ビット出力のうち 14 ビットが使用されます。
私たちのテストでは、CRC16 アルゴリズムはさまざまな種類のキーを 16384 個のスロットにスムーズに分配できます。
クラスター ノードのプロパティ
各ノードにはクラスター内で一意の ID があり、ノードの最初の起動時に /dev/urandom によって生成される 160 ビットの乱数です。
ノードはその ID を設定ファイルに保存します。設定ファイルが削除されない限り、ノードは常にこの ID を使用します。
ノードIDは、クラスター内の各ノードを識別するために使用されます。 ノードは、ノード ID を変更せずに、その IP とポート番号を変更できます。 クラスターは IP/ポート番号の変更を自動的に識別し、ゴシップ プロトコルを通じてこの情報を他のノードにブロードキャストできます。
以下は各ノードが持つ関連情報であり、ノードはこの情報を他のノードに送信します:
ノードが使用する IP アドレスと TCP ポート番号。
ノードフラグ。
ノードが処理を担当するハッシュスロット。
ノードがクラスター接続を使用して最後に PING パケットを送信した時間。
ノードが応答として PONG パケットを最後に受信した時刻。
クラスターがノードをオフラインとしてマークする時間。
このノードのスレーブノードの数。
ノードがスレーブノードの場合、マスターノードのノードIDを記録します。 これがマスター ノードの場合、[マスター ノード ID] 列の値は 0000000 です。
上記の情報の一部は、クラスター内の任意のノード (マスター ノードまたはスレーブ ノード) に CLUSTER NODES コマンドを送信することで取得できます。
以下は、3 つのノードで構成されるクラスター内のマスター ノードに CLUSTER NODES コマンドを送信する例です。
$ redis-cli cluster nodes d1861060fe6a534d42d8a19aeb36600e18785e04 :0 myself - 0 1318428930 connected 0-1364 3886e65cc906bfd9b1f7e7bde468726a052d1dae 127.0.0.1:6380 master - 1318428930 1318428931 connected 1365-2729 d289c575dcbc4bdd2931585fd4339089e461a27d 127.0.0.1:6381 master - 1318428931 1318428931 connected 2730-4095
上記の 3 行の情報では、それぞれ左から右にフィールドは、ノード ID、IP アドレスとポート番号、フラグ、最後に PING を送信した時刻、最後に PONG を受信した時刻、接続ステータス、およびノードが処理を担当するスロットです。
ノードハンドシェイク(実装)
ノードは、PINGパケットが信頼できないノードからのものであっても、常にクラスター接続ポートからの接続リクエストを受け入れ、受信したPINGパケットに応答します。
ただし、ノードは PING を除き、クラスター ノードから送信されない他のすべてのパケットを拒否します。
別のノードが同じクラスターに属していることをノードに認識させるには、次の 2 つの方法しかありません:
ノードは、別のノードに MEET メッセージを送信して、メッセージを受信するノードに、メッセージを送信しているノードであることを強制的に認識させることができます。メッセージは「クラスターの一部です」です。 管理者が CLUSTER MEET ip port コマンドを明示的に送信した場合にのみ、ノードは MEET 情報を別のノードに送信します。
さらに、信頼されたノードがサードパーティ ノードの情報を別のノードに配布すると、情報を受信したノードもサードパーティ ノードをクラスタのメンバーとして識別します。 つまり、A が B を知っており、B が C を知っており、B が C に関する情報を A に広めた場合、A も C をクラスターのメンバーとして認識し、C に接続しようとします。
これは、新しいノードをクラスターに追加すると、その新しいノードは最終的にクラスター内の既存の他のすべてのノードに接続されることを意味します。
これは、管理者が CLUSTER MEET コマンドを使用して信頼関係を明示的に指定している限り、クラスターが他のノードを自動的に検出できることを示しています。
このノード識別メカニズムにより、IP アドレスの変更やその他のネットワーク イベントによる異なる Redis クラスターの予期しない組み合わせ (混合) が防止され、クラスターがより堅牢になります。
ノードのネットワーク接続が切断されると、そのノードは他の既知のノードにアクティブに接続します。
ターンを移動しました
一个 Redis 客户端可以向集群中的任意节点(包括从节点)发送命令请求。 节点会对命令请求进行分析, 如果该命令是集群可以执行的命令, 那么节点会查找这个命令所要处理的键所在的槽。
如果要查找的哈希槽正好就由接收到命令的节点负责处理, 那么节点就直接执行这个命令。
另一方面, 如果所查找的槽不是由该节点处理的话, 节点将查看自身内部所保存的哈希槽到节点 ID 的映射记录, 并向客户
端回复一个 MOVED 错误。
以下是一个 MOVED 错误的例子:
GET x -MOVED 3999 127.0.0.1:6381
错误信息包含键 x 所属的哈希槽 3999 , 以及负责处理这个槽的节点的 IP 和端口号 127.0.0.1:6381 。 客户端需要根据这个 IP 和端口号, 向所属的节点重新发送一次 GET 命令请求。
注意, 即使客户端在重新发送 GET 命令之前, 等待了非常久的时间, 以至于集群又再次更改了配置, 使得节点 127.0.0.1:6381 已经不再处理槽 3999 , 那么当客户端向节点 127.0.0.1:6381 发送 GET 命令的时候, 节点将再次向客户端返回 MOVED 错误, 指示现在负责处理槽 3999 的节点。
虽然我们用 ID 来标识集群中的节点, 但是为了让客户端的转向操作尽可能地简单, 节点在 MOVED 错误中直接返回目标节点的 IP 和端口号, 而不是目标节点的 ID 。
虽然不是必须的, 但一个客户端应该记录(memorize)下“槽 3999 由节点 127.0.0.1:6381 负责处理“这一信息, 这样当再次有命令需要对槽 3999 执行时, 客户端就可以加快寻找正确节点的速度。
注意, 当集群处于稳定状态时, 所有客户端最终都会保存有一个哈希槽至节点的映射记录(map of hash slots to nodes), 使得集群非常高效: 客户端可以直接向正确的节点发送命令请求, 无须转向、代理或者其他任何可能发生单点故障(single point failure)的实体(entiy)。
除了 MOVED 转向错误之外, 一个客户端还应该可以处理稍后介绍的 ASK 转向错误。
集群在线重配置(live reconfiguration)
Redis 集群支持在集群运行的过程中添加或者移除节点。
实际上, 节点的添加操作和节点的删除操作可以抽象成同一个操作, 那就是, 将哈希槽从一个节点移动到另一个节点:
添加一个新节点到集群, 等于将其他已存在节点的槽移动到一个空白的新节点里面。
从集群中移除一个节点, 等于将被移除节点的所有槽移动到集群的其他节点上面去。
因此, 实现 Redis 集群在线重配置的核心就是将槽从一个节点移动到另一个节点的能力。 因为一个哈希槽实际上就是一些键的集合, 所以 Redis 集群在重哈希(rehash)时真正要做的, 就是将一些键从一个节点移动到另一个节点。
要理解 Redis 集群如何将槽从一个节点移动到另一个节点, 我们需要对 CLUSTER 命令的各个子命令进行介绍, 这些命理负责管理集群节点的槽转换表(slots translation table)。
以下是 CLUSTER 命令可用的子命令:
CLUSTER ADDSLOTS slot1 [slot2] ... [slotN] CLUSTER DELSLOTS slot1 [slot2] ... [slotN] CLUSTER SETSLOT slot NODE node CLUSTER SETSLOT slot MIGRATING node CLUSTER SETSLOT slot IMPORTING node
最开头的两条命令 ADDSLOTS 和 DELSLOTS 分别用于向节点指派(assign)或者移除节点, 当槽被指派或者移除之后, 节点会将这一信息通过 Gossip 协议传播到整个集群。 ADDSLOTS 命令通常在新创建集群时, 作为一种快速地将各个槽指派给各个节点的手段来使用。
CLUSTER SETSLOT slot NODE node 子命令可以将指定的槽 slot 指派给节点 node 。
至于 CLUSTER SETSLOT slot MIGRATING node 命令和 CLUSTER SETSLOT slot IMPORTING node 命令, 前者用于将给定节点 node 中的槽 slot 迁移出节点, 而后者用于将给定槽 slot 导入到节点 node :
当一个槽被设置为 MIGRATING 状态时, 原来持有这个槽的节点仍然会继续接受关于这个槽的命令请求, 但只有命令所处理的键仍然存在于节点时, 节点才会处理这个命令请求。
如果命令所使用的键不存在与该节点, 那么节点将向客户端返回一个 -ASK 转向(redirection)错误, 告知客户端, 要将命令请求发送到槽的迁移目标节点。
当一个槽被设置为 IMPORTING 状态时, 节点仅在接收到 ASKING 命令之后, 才会接受关于这个槽的命令请求。
如果客户端没有向节点发送 ASKING 命令, 那么节点会使用 -MOVED 转向错误将命令请求转向至真正负责处理这个槽的节点。
上面关于 MIGRATING 和 IMPORTING 的说明有些难懂, 让我们用一个实际的实例来说明一下。
假设现在, 我们有 A 和 B 两个节点, 并且我们想将槽 8 从节点 A 移动到节点 B , 于是我们:
向节点 B 发送命令 CLUSTER SETSLOT 8 IMPORTING A
向节点 A 发送命令 CLUSTER SETSLOT 8 MIGRATING B
每当客户端向其他节点发送关于哈希槽 8 的命令请求时, 这些节点都会向客户端返回指向节点 A 的转向信息:
如果命令要处理的键已经存在于槽 8 里面, 那么这个命令将由节点 A 处理。
如果命令要处理的键未存在于槽 8 里面(比如说,要向槽添加一个新的键), 那么这个命令由节点 B 处理。
这种机制将使得节点 A 不再创建关于槽 8 的任何新键。
与此同时, 一个特殊的客户端 redis-trib 以及 Redis 集群配置程序(configuration utility)会将节点 A 中槽 8 里面的键移动到节点 B 。
键的移动操作由以下两个命令执行:
CLUSTER GETKEYSINSLOT slot count
上面的命令会让节点返回 count 个 slot 槽中的键, 对于命令所返回的每个键, redis-trib 都会向节点 A 发送一条 MIGRATE 命令, 该命令会将所指定的键原子地(atomic)从节点 A 移动到节点 B (在移动键期间,两个节点都会处于阻塞状态,以免出现竞争条件)。
以下为 MIGRATE 命令的运作原理:
MIGRATE target_host target_port key target_database id timeout
执行 MIGRATE 命令的节点会连接到 target 节点, 并将序列化后的 key 数据发送给 target , 一旦 target 返回 OK , 节点就将自己的 key 从数据库中删除。
从一个外部客户端的视角来看, 在某个时间点上, 键 key 要么存在于节点 A , 要么存在于节点 B , 但不会同时存在于节点 A 和节点 B 。
因为 Redis 集群只使用 0 号数据库, 所以当 MIGRATE 命令被用于执行集群操作时, target_database 的值总是 0 。
target_database 参数的存在是为了让 MIGRATE 命令成为一个通用命令, 从而可以作用于集群以外的其他功能。
我们对 MIGRATE 命令做了优化, 使得它即使在传输包含多个元素的列表键这样的复杂数据时, 也可以保持高效。
不过, 尽管 MIGRATE 非常高效, 对一个键非常多、并且键的数据量非常大的集群来说, 集群重配置还是会占用大量的时间, 可能会导致集群没办法适应那些对于响应时间有严格要求的应用程序。
ASK 转向
在之前介绍 MOVED 转向的时候, 我们说除了 MOVED 转向之外, 还有另一种 ASK 转向。
当节点需要让一个客户端长期地(permanently)将针对某个槽的命令请求发送至另一个节点时, 节点向客户端返回 MOVED 转向。
另一方面, 当节点需要让客户端仅仅在下一个命令请求中转向至另一个节点时, 节点向客户端返回 ASK 转向。
比如说, 在我们上一节列举的槽 8 的例子中, 因为槽 8 所包含的各个键分散在节点 A 和节点 B 中, 所以当客户端在节点 A 中没找到某个键时, 它应该转向到节点 B 中去寻找, 但是这种转向应该仅仅影响一次命令查询, 而不是让客户端每次都直接去查找节点 B : 在节点 A 所持有的属于槽 8 的键没有全部被迁移到节点 B 之前, 客户端应该先访问节点 A , 然后再访问节点 B 。
因为这种转向只针对 16384 个槽中的其中一个槽, 所以转向对集群造成的性能损耗属于可接受的范围。
因为上述原因, 如果我们要在查找节点 A 之后, 继续查找节点 B , 那么客户端在向节点 B 发送命令请求之前, 应该先发送一个 ASKING 命令, 否则这个针对带有 IMPORTING 状态的槽的命令请求将被节点 B 拒绝执行。
接收到客户端 ASKING 命令的节点将为客户端设置一个一次性的标志(flag), 使得客户端可以执行一次针对 IMPORTING 状态的槽的命令请求。
从客户端的角度来看, ASK 转向的完整语义(semantics)如下:
如果客户端接收到 ASK 转向, 那么将命令请求的发送对象调整为转向所指定的节点。
先发送一个 ASKING 命令,然后再发送真正的命令请求。
不必更新客户端所记录的槽 8 至节点的映射: 槽 8 应该仍然映射到节点 A , 而不是节点 B 。
一旦节点 A 针对槽 8 的迁移工作完成, 节点 A 在再次收到针对槽 8 的命令请求时, 就会向客户端返回 MOVED 转向, 将关于槽 8 的命令请求长期地转向到节点 B 。
クライアントでバグが発生し、スロット 8 が途中でノード B にマップされた場合でも、クライアントが ASKING コマンドを送信しない限り、クライアントはコマンド リクエストの送信時に MOVED エラーが発生し、コマンド リクエストをリダイレクトして戻されることに注意してください。ノードA。
フォールトトレランス
ノード障害検出
ノード障害検出の実装方法は次のとおりです:
ノードが別のノードに PING コマンドを送信したが、ターゲット ノードがそのノード内で PING コマンドを返せない場合指定された時間制限 応答すると、コマンドを送信するノードはターゲット ノードを PFAIL (失敗の可能性、失敗した可能性) としてマークします。
PING コマンドからの応答を待つ時間制限は「ノード タイムアウト」と呼ばれ、ノードごとの設定です。
ノードが他のノードに PING コマンドを送信するたびに、ノードが知っているノードに関する 3 つの情報がランダムにブロードキャストされます。その 1 つは、ノードが PFAIL または FAIL としてマークされているかどうかです。
ノードが他のノードから情報を受信すると、他のノードによって障害が発生したとマークされたノードが記録されます。 これを障害レポートと呼びます。
ノードがノードを PFAIL としてマークしており、ノードが受信した明示的な障害レポートに基づいて、クラスター内の他のほとんどのマスター ノードもノードが障害状態に入ったと信じている場合、ノードはノードのステータスを更新します。失敗したノードはFAILとしてマークされます。
ノードが FAIL としてマークされると、ノードの障害に関する情報がクラスター全体にブロードキャストされ、この情報を受信したすべてのノードは障害が発生したノードを FAIL としてマークします。
簡単に言えば、ノードが別のノードを無効としてマークしたい場合は、まず他のノードに意見を求め、マスターノードの大多数の同意を得る必要があります。
期限切れの障害レポートは削除されるため、マスターノードがノードをFAILとしてマークしたい場合は、最後に受信した障害レポートに基づいている必要があります。
ノードのFAILステータスは、次の2つの状況で削除されます:
FAILとしてマークされたノードがスレーブノードの場合、ノードがオンラインに戻ると、FAILマークは削除されます。
スレーブ ノードが FAIL 状態にあるかどうかによって、必要に応じてスレーブ ノードをマスター ノードに昇格できるかどうかが決まるため、スレーブ ノードの FAIL 状態を再度取得しても意味がありません。
マスター ノードが FAIL としてマークされた後、ノード タイムアウト期間の 4 倍に 10 秒を加えた後、マスター ノードのスロットのフェイルオーバー操作が完了しておらず、マスター ノードがオンラインに戻っている場合は、このノードの FAIL マーク。
2 番目のケースでは、フェイルオーバーが正常に完了せず、マスター ノードがオンラインに戻った場合、クラスターは引き続き元のマスター ノードを使用するため、管理者の介入は不要になります。
クラスターステータス検出 (部分的に実装)
クラスター内で構成変更が発生するたびに (ハッシュスロットの更新、またはノードが障害状態になる可能性があります)、クラスター内の各ノードはステータスをチェックします。既知のノード。
構成が処理されると、クラスターは次の 2 つの状態のいずれかになります:
FAIL: クラスターは正しく動作できません。 クラスター内のノードが障害状態になると、クラスターはコマンド要求を処理できなくなり、コマンド要求ごとにエラー応答が返されます。
OK: クラスターは正常に動作しており、16384 スロットすべての処理を担当するノードはどれも FAIL としてマークされていません。
これは、クラスター内のハッシュ スロットの一部だけが使用されていない場合でも、クラスター全体がコマンドの処理を停止することを意味します。
ただし、ノードに問題が発生してから FAIL とマークされるまでの間、クラスターは引き続き正常に動作するため、ある時点では、クラスターは 16384 スロットのサブセットに対してのみコマンドを処理できる可能性があります。聞く。
クラスターが FAIL 状態になる 2 つの状況は次のとおりです:
このスロットの処理を担当するノードが FAIL 状態になったため、少なくとも 1 つのハッシュ スロットが使用できません。
クラスター内のほとんどのマスターノードがオフラインになりました。ほとんどのマスター ノードが PFAIL 状態になると、クラスターも FAIL 状態になります。
ノードを PFAIL 状態から FAIL 状態に変更するには、マスター ノードの過半数が投票する必要があるため、2 番目のチェックが必要です。ただし、クラスター内のほとんどのマスター ノードが障害状態になると、ノードをマークする方法がありません。 1 つまたは 2 つのノードだけで FAIL 状態として認識されます。
したがって、2番目のチェック条件では、クラスタ内のほとんどのマスターノードがオフライン状態になれば、クラスターはこれらのマスターノードの意見を求めずにノードをFAIL状態と判断することができます。クラスター全体がコマンド要求の処理を停止します。
スレーブノードの選択
一旦某个主节点进入 FAIL 状态, 如果这个主节点有一个或多个从节点存在, 那么其中一个从节点会被升级为新的主节点, 而其他从节点则会开始对这个新的主节点进行复制。
新的主节点由已下线主节点属下的所有从节点中自行选举产生, 以下是选举的条件:
这个节点是已下线主节点的从节点。
已下线主节点负责处理的槽数量非空。
从节点的数据被认为是可靠的, 也即是, 主从节点之间的复制连接(replication link)的断线时长不能超过节点超时时限(node timeout)乘以 REDIS_CLUSTER_SLAVE_VALIDITY_MULT 常量得出的积。
如果一个从节点满足了以上的所有条件, 那么这个从节点将向集群中的其他主节点发送授权请求, 询问它们, 是否允许自己(从节点)升级为新的主节点。
如果发送授权请求的从节点满足以下属性, 那么主节点将向从节点返回 FAILOVER_AUTH_GRANTED 授权, 同意从节点的
升级要求:
发送授权请求的是一个从节点, 并且它所属的主节点处于 FAIL 状态。
在已下线主节点的所有从节点中, 这个从节点的节点 ID 在排序中是最小的。
这个从节点处于正常的运行状态: 它没有被标记为 FAIL 状态, 也没有被标记为 PFAIL 状态。
一旦某个从节点在给定的时限内得到大部分主节点的授权, 它就会开始执行以下故障转移操作:
通过 PONG 数据包(packet)告知其他节点, 这个节点现在是主节点了。
通过 PONG 数据包告知其他节点, 这个节点是一个已升级的从节点(promoted slave)。
接管(claiming)所有由已下线主节点负责处理的哈希槽。
显式地向所有节点广播一个 PONG 数据包, 加速其他节点识别这个节点的进度, 而不是等待定时的 PING / PONG 数据包。
所有其他节点都会根据新的主节点对配置进行相应的更新,特别地:
所有被新的主节点接管的槽会被更新。
已下线主节点的所有从节点会察觉到 PROMOTED 标志, 并开始对新的主节点进行复制。
如果已下线的主节点重新回到上线状态, 那么它会察觉到 PROMOTED 标志, 并将自身调整为现任主节点的从节点。
在集群的生命周期中, 如果一个带有 PROMOTED 标识的主节点因为某些原因转变成了从节点, 那么该节点将丢失它所带有的 PROMOTED 标识。
发布/订阅(已实现,但仍然需要改善)
在一个 Redis 集群中, 客户端可以订阅任意一个节点, 也可以向任意一个节点发送信息, 节点会对客户端所发送的信息进行转发。
在目前的实现中, 节点会将接收到的信息广播至集群中的其他所有节点, 在将来的实现中, 可能会使用 bloom filter 或者其他算法来优化这一操作。
附录 A: CRC16 算法的 ANSI 实现参考
/* * Copyright 2001-2010 Georges Menie (www.menie.org) * Copyright 2010 Salvatore Sanfilippo (adapted to Redis coding style) * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the University of California, Berkeley nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* CRC16 implementation acording to CCITT standards. * * Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the * following parameters: * * Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN" * Width : 16 bit * Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1) * Initialization : 0000 * Reflect Input byte : False * Reflect Output CRC : False * Xor constant to output CRC : 0000 * Output for "123456789" : 31C3 */ static const uint16_t crc16tab[256]= { 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 }; uint16_t crc16(const char *buf, int len) { int counter; uint16_t crc = 0; for (counter = 0; counter < len; counter++) crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF]; return crc; }
相关推荐:
以上がRedisクラスター仕様の知識を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。