Maison  >  Article  >  développement back-end  >  Explication détaillée des connaissances sur les spécifications du cluster Redis

Explication détaillée des connaissances sur les spécifications du cluster Redis

小云云
小云云original
2017-12-14 14:56:251526parcourir

Cet article présente principalement l'explication détaillée des spécifications du cluster Redis. Nous expliquerons à partir du plus basique ce qu'est le cluster Redis et les fonctions du cluster Redis, impliquant la détection des pannes de nœuds, la détection de l'état du cluster, l'élection des nœuds esclaves et d'autres contenus connexes. Il est plus détaillé et les amis peuvent s'y référer, j'espère que cela pourra aider tout le monde.

Introduction

Ce document est un document de spécification de la fonction cluster Redis en cours de développement. Le document est divisé en deux parties :

La première partie présente les fonctions qui ont été implémentées dans la branche unstable.
La deuxième partie présente les fonctionnalités qui ne sont pas encore implémentées.

Le contenu de chaque partie du document peut changer à mesure que la conception de la fonction cluster est modifiée. Parmi elles, la probabilité de modification des fonctions non implémentées est supérieure à celle des fonctions implémentées.

Cette spécification contient toutes les connaissances nécessaires pour écrire une bibliothèque client, mais veuillez noter que certains des détails répertoriés ici peuvent changer à l'avenir.

Qu'est-ce que le cluster Redis ?

Le cluster Redis est une implémentation Redis distribuée et tolérante aux pannes. Les fonctions qui peuvent être utilisées par le cluster sont un sous-ensemble des fonctions qui peuvent être utilisées par Redis autonome ordinaire. (sous-ensemble).

Il n'y a pas de nœud central ou de nœud proxy dans le cluster Redis. L'un des principaux objectifs de conception du cluster est d'atteindre une évolutivité linéaire.

Le cluster Redis sacrifie une certaine tolérance aux pannes afin d'assurer la cohérence : le système assurera une résistance limitée à la déconnexion du réseau (net split) et à la panne de nœud (panne de nœud) Maintenir autant que possible la cohérence des données sous le principe de la force.

Le cluster traite la défaillance du nœud comme l'un des cas particuliers de déconnexion du réseau.

La fonction de tolérance aux pannes du cluster est réalisée en utilisant des nœuds avec deux rôles : nœud maître (maître) et nœud esclave (esclave) :

Le nœud maître et le nœud esclave utilise exactement la même implémentation de serveur et leurs fonctions sont exactement les mêmes, mais le nœud esclave n'est généralement utilisé que pour remplacer le nœud maître défaillant.
Cependant, si vous n'avez pas besoin de garantir la cohérence des opérations « écrire d'abord, lire plus tard » (cohérence lecture après écriture), vous pouvez utiliser des nœuds esclaves pour exécuter des requêtes en lecture seule.

Redis Cluster implémente un sous-ensemble de fonctions

Redis Cluster implémente toutes les commandes pour traiter une seule clé de base de données dans Redis autonome.

Les opérations de calcul complexes pour plusieurs clés de base de données, telles que les opérations d'union et les opérations de collecte d'ensembles, ne sont pas non plus implémentées. Les commandes qui nécessitent théoriquement l'utilisation de plusieurs clés de base de données à partir de plusieurs nœuds. Non mis en œuvre.

À l'avenir, les utilisateurs pourront peut-être utiliser la commande MIGRATE COPY pour effectuer des opérations en lecture seule sur plusieurs clés de base de données dans le nœud de calcul du cluster, mais le cluster lui-même ne mettra pas en œuvre ces besoins. commandes multi-clés pour déplacer plusieurs clés de base de données autour de plusieurs nœuds.

Le cluster Redis ne prend pas en charge plusieurs fonctions de base de données comme Redis autonome. Le cluster utilise uniquement la base de données par défaut n° 0 et ne peut pas utiliser la commande SELECT.

Les clients et les serveurs du protocole du cluster Redis

Les nœuds du cluster Redis ont les responsabilités suivantes :

Détenir des paires clé-valeur données.
Enregistrez l'état du cluster, y compris le mappage des clés vers les nœuds droits.
Découvrez automatiquement d'autres nœuds, identifiez les nœuds qui ne fonctionnent pas correctement et élisez de nouveaux nœuds maîtres parmi les nœuds esclaves si nécessaire.

Afin d'effectuer les tâches listées ci-dessus, chaque nœud du cluster établit un « bus cluster » avec d'autres nœuds. Cette connexion est une connexion TCP utilisant le protocole de communication binaire.

Le protocole Gossip est utilisé entre les nœuds pour effectuer les tâches suivantes :

Propagation des informations sur le cluster pour découvrir de nouveaux nœuds.
Envoyez des paquets PING à d'autres nœuds pour vérifier si le nœud cible fonctionne correctement.
Envoyer des informations sur le cluster lorsque des événements spécifiques se produisent.

De plus, les connexions au cluster sont également utilisées pour publier ou s'abonner aux informations du cluster.

Étant donné que les nœuds du cluster ne peuvent pas proxy les demandes de commande, le client doit transmettre lui-même la demande de commande aux autres nœuds lorsque le nœud renvoie une erreur de redirection -MOVED ou -ASK.

Parce que le client est libre d'envoyer des demandes de commande à n'importe quel nœud du cluster et, si nécessaire, peut transmettre la commande au bon nœud en fonction des informations fournies par l'erreur de pilotage, donc en théorie , le client n'a pas besoin d'enregistrer les informations sur l'état du cluster.

Cependant, si le client peut enregistrer les informations de mappage entre les clés et les nœuds, il peut réduire efficacement le nombre de redirections possibles, améliorant ainsi l'efficacité de l'exécution des commandes.

Modèle de distribution de clés

L'espace clé du cluster Redis est divisé en 16384 emplacements, et le nombre maximum de nœuds dans le cluster est également de 16384.

Le nombre maximum de nœuds recommandé est d'environ 1 000.

Chaque masternode est responsable du traitement d'une partie des 16384 emplacements de hachage.

Quand on dit qu'un cluster est dans un état "stable", on veut dire que le cluster n'effectue pas d'opérations de reconfiguration et que chaque slot de hachage est traité par un seul nœud.

La reconfiguration fait référence au déplacement de certains/certains emplacements d'un nœud à un autre.

Un nœud maître peut avoir n'importe quel nombre de nœuds esclaves. Ces nœuds esclaves sont utilisés pour remplacer le nœud maître lorsque le réseau est déconnecté ou que le nœud tombe en panne.

Voici l'algorithme responsable du mappage des clés aux emplacements :

HASH_SLOT = CRC16(key) mod 16384


Voici les paramètres utilisés par l'algorithme :

Nom de l'algorithme : XMODEM (aussi appelé ZMODEM ou CRC-16/ACORN)
Longueur du résultat : 16 bits
Nombre polynomial ( poly) : 1021 (c'est-à-dire x16 + x12 + x5 + 1)
Valeur d'initialisation : 0000
Reflect Octet d'entrée : False
Reflect Output CRC : False
Constante Xor à sortir CRC : 0000
La sortie de cet algorithme pour l'entrée "123456789" : 31C3

Donné en annexe A Implémentation de l'algorithme CRC16 utilisé par le cluster.

14 bits de la sortie 16 bits produite par l'algorithme CRC16 sont utilisés.
Lors de nos tests, l'algorithme CRC16 a fait du bon travail en répartissant en douceur différents types de clés dans 16 384 emplacements.

Attributs du nœud du cluster

Chaque nœud a un identifiant unique dans le cluster. L'ID est un nombre aléatoire de 160 bits représenté en hexadécimal. lorsque le nœud est démarré pour la première fois.

Le nœud enregistrera son ID dans le fichier de configuration. Tant que le fichier de configuration n'est pas supprimé, le nœud utilisera toujours cet ID.

L'ID de nœud identifie chaque nœud du cluster. Un nœud peut modifier son adresse IP et son numéro de port sans modifier l'ID du nœud. Le cluster peut identifier automatiquement les changements dans les numéros IP/port et diffuser ces informations à d'autres nœuds via le protocole Gossip.

Voici les informations associées dont dispose chaque nœud, et le nœud enverra ces informations à d'autres nœuds :

L'adresse IP et le numéro de port TCP utilisés par le nœud .
Drapeaux de nœud.
L'emplacement de hachage que le nœud est responsable du traitement.
La dernière fois qu'un nœud a envoyé un paquet PING à l'aide d'une connexion de cluster.
La dernière fois que le nœud a reçu un paquet PONG dans une réponse.
L'heure à laquelle le cluster marque le nœud comme hors ligne.
Le nombre de nœuds esclaves de ce nœud.
Si le nœud est un nœud esclave, il enregistrera l'ID du nœud maître. S'il s'agit d'un nœud maître, la valeur dans la colonne ID du nœud maître est 0000000.

Une partie des informations ci-dessus peut être obtenue en envoyant la commande CLUSTER NODES à n'importe quel nœud du cluster (soit le nœud maître, soit le nœud esclave).

Ce qui suit est un exemple d'envoi de la commande CLUSTER NODES au nœud maître dans un cluster, composé de trois nœuds :

$ 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

Dans les trois lignes d'informations listées ci-dessus, les champs de gauche à droite sont : l'ID du nœud, l'adresse IP et le numéro de port, le drapeau, la dernière fois pour envoyer du PING, la dernière fois pour recevoir du PONG, L'état de la connexion , l'emplacement que le nœud est responsable de la gestion.

Poignée de liaison du nœud (implémentée)

Le nœud accepte toujours la demande de connexion du port de connexion du cluster et répond au paquet PING reçu même si ce paquet PING provient. un nœud non fiable.

Cependant, à l'exception du PING, le nœud rejettera tous les autres paquets qui ne proviennent pas du nœud du cluster.

Pour qu'un nœud reconnaisse qu'un autre nœud appartient au même cluster, il n'y a que deux méthodes :

Un nœud peut envoyer un message MEET à un autre nœud Forcer. le nœud recevant le message reconnaît le nœud qui envoie le message en tant que membre du cluster. Un nœud enverra des informations MEET à un autre nœud uniquement si l'administrateur lui envoie explicitement la commande CLUSTER MEET ip port.
De plus, si un nœud de confiance diffuse les informations d'un nœud tiers vers un autre nœud, le nœud recevant les informations identifiera également le nœud tiers comme membre du cluster. Autrement dit, si A connaît B, B connaît C et que B diffuse des informations sur C à A, alors A reconnaîtra également C comme membre du cluster et tentera de se connecter à C.

Cela signifie que si nous ajoutons un ou plusieurs nouveaux nœuds à un cluster, alors ce/ces nouveaux nœuds seront éventuellement connectés à tous les autres nœuds déjà présents dans le cluster.

Cela signifie que tant que l'administrateur spécifie explicitement la relation de confiance à l'aide de la commande CLUSTER MEET, le cluster peut découvrir automatiquement d'autres nœuds.

Ce mécanisme d'identification de nœud rend le cluster plus robuste en empêchant les combinaisons (mélanges) inattendues de différents clusters Redis en raison de changements d'adresse IP ou d'autres événements réseau.

Lorsque la connexion réseau d'un nœud est déconnectée, il se connectera activement à d'autres nœuds connus.

Déplacé

一个 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 。

Notez que même si un bug se produit sur le client et que l'emplacement 8 est mappé prématurément au nœud B, tant que le client n'envoie pas la commande ASKING, le client rencontrera une erreur MOVED lors de l'envoi d'une demande de commande et tournera retour au nœud A.

Tolérance aux pannes

Détection de panne de nœud

Voici la méthode de mise en œuvre de la détection de panne de nœud :

Lorsqu'un nœud envoie une commande PING à un autre nœud, mais que le nœud cible ne parvient pas à renvoyer une réponse à la commande PING dans un délai donné, le nœud qui envoie la commande marquera le nœud cible comme PFAIL (échec possible).
Le délai d'attente de la réponse de la commande PING est appelé « délai d'attente du nœud » et est un paramètre par nœud.
Chaque fois qu'un nœud envoie une commande PING à d'autres nœuds, il diffusera aléatoirement trois informations sur les nœuds qu'il connaît. L'une des informations est de savoir si le nœud a été marqué comme PFAIL ou FAIL.
Lorsqu'un nœud reçoit des informations d'autres nœuds, il enregistrera les nœuds marqués comme ayant échoué par d'autres nœuds. C’est ce qu’on appelle un rapport d’échec.
Si un nœud a marqué un nœud comme PFAIL et, sur la base du rapport d'échec explicite reçu par le nœud, la plupart des autres nœuds maîtres du cluster croient également que le nœud est entré dans un état d'échec, alors le nœud le fera. marqué ÉCHEC.
Une fois qu'un nœud est marqué comme FAIL, les informations indiquant que le nœud a échoué seront diffusées à l'ensemble du cluster, et tous les nœuds qui reçoivent ces informations marqueront le nœud défaillant comme FAIL.

Pour faire simple, si un nœud veut marquer un autre nœud comme invalide, il doit d'abord demander leur avis aux autres nœuds et obtenir le consentement de la majorité des nœuds maîtres.

Étant donné que les rapports d'échec expirés seront supprimés, si le nœud maître souhaite marquer un nœud comme FAIL, il doit être basé sur le rapport d'échec reçu le plus récemment.

Dans les deux situations suivantes, l'état FAIL du nœud sera supprimé :

Si le nœud marqué FAIL est un nœud esclave, alors lorsque le nœud reviendra en ligne, la marque FAIL sera supprimée.
Il ne sert à rien de conserver l'état FAIL du nœud esclave, car il ne gère aucun slot. Le fait qu'un nœud esclave soit dans l'état FAIL détermine si le nœud esclave peut être promu au nœud maître en cas de besoin.
Si après qu'un nœud maître est marqué comme FAIL, après quatre fois le délai d'expiration du nœud, plus dix secondes, l'opération de basculement pour l'emplacement du nœud maître n'a pas été terminée et le nœud maître a échoué. S'il revient en ligne, supprimez la marque FAIL sur ce nœud.

Dans le deuxième cas, si le basculement échoue et que le nœud maître revient en ligne, le cluster continuera à utiliser le nœud maître d'origine, éliminant ainsi le besoin d'intervention de l'administrateur.

Détection de l'état du cluster (partiellement implémentée)

Chaque fois qu'un changement de configuration se produit dans le cluster (il peut s'agir d'une mise à jour d'un emplacement de hachage ou d'un nœud entre dans un état d'échec) , chaque nœud du cluster analysera les nœuds qu'il connaît.

Une fois la configuration traitée, le cluster entrera dans l'un des deux états suivants :

FAIL : Le cluster ne peut pas fonctionner correctement. Lorsqu'un nœud du cluster entre dans un état d'échec, le cluster ne peut traiter aucune demande de commande. Pour chaque demande de commande, le nœud du cluster renvoie une réponse d'erreur.
OK : le cluster fonctionne normalement et aucun des nœuds responsables du traitement des 16 384 emplacements n'est marqué comme FAIL.

Cela signifie que même si seulement une partie des emplacements de hachage du cluster ne sont pas utilisés, l'ensemble du cluster cessera de traiter les commandes.

Cependant, le cluster fonctionnera toujours normalement pendant la période entre le moment où un nœud rencontre un problème et celui où il est marqué comme FAIL, donc à un moment donné, le cluster peut encore être capable de gérer seulement 16 384 emplacements. Un sous-ensemble des demandes de commande.

Voici deux situations dans lesquelles le cluster entre dans l'état FAIL :

Au moins un emplacement de hachage est indisponible car le nœud responsable du traitement de cet emplacement est entré dans l'état FAIL. État.
La plupart des nœuds maîtres du cluster sont hors ligne. Lorsque la plupart des nœuds maîtres entrent dans l’état PFAIL, le cluster entre également dans l’état FAIL.

La deuxième vérification est nécessaire car pour faire passer un nœud de l'état PFAIL à l'état FAIL, une majorité de nœuds maîtres doit voter. Cependant, lorsqu'une majorité de nœuds maîtres du cluster entrent tous. l'état d'échec, il n'y a aucun moyen de marquer un nœud comme état FAIL par seulement un ou deux nœuds.

Par conséquent, avec la deuxième condition de vérification, tant que la plupart des nœuds maîtres du cluster entrent dans l'état hors ligne, le cluster peut modifier un certain nœud maître sans demander l'avis de ces nœuds maîtres. Le nœud est jugé comme étant à l'état FAIL, ce qui entraîne l'arrêt du traitement des demandes de commande par l'ensemble du cluster.

Élection du nœud esclave

一旦某个主节点进入 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集群规范(一)

Redis集群搭建全记录

redis集群实战

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn