In diesem Artikel werden hauptsächlich die Redis-Cluster-Spezifikationen ausführlich erläutert. Wir erklären zunächst einmal, was ein Redis-Cluster ist und welche Funktionen der Redis-Cluster hat, einschließlich der Knotenfehlererkennung, der Clusterstatuserkennung, der Slave-Knotenauswahl und anderer verwandter Inhalte. Es ist detaillierter und braucht Freunde, die darauf verweisen können. Ich hoffe, es kann allen helfen.
Einführung
Dieses Dokument ist ein Spezifikationsdokument für die in der Entwicklung befindliche Redis-Clusterfunktion. Das Dokument ist in zwei Teile unterteilt:
Im ersten Teil werden die Funktionen vorgestellt, die im Unstable-Zweig implementiert wurden.
Im zweiten Teil werden die Funktionen vorgestellt, die noch nicht implementiert sind.
Der Inhalt jedes Teils des Dokuments kann sich ändern, wenn das Design der Clusterfunktion geändert wird. Dabei ist die Wahrscheinlichkeit einer Änderung nicht implementierter Funktionen höher als die der implementierten Funktionen.
Diese Spezifikation enthält das gesamte Wissen, das zum Schreiben einer Client-Bibliothek erforderlich ist. Bitte beachten Sie jedoch, dass sich einige der hier aufgeführten Details in Zukunft ändern können.
Was ist ein Redis-Cluster?
Redis-Cluster ist eine verteilte, fehlertolerante Redis-Implementierung. Die Funktionen, die vom Cluster verwendet werden können, sind eine Teilmenge der Funktionen, die von gewöhnlichen eigenständigen Redis verwendet werden können. (Teilmenge).
Es gibt keinen zentralen Knoten oder Proxy-Knoten im Redis-Cluster. Eines der Hauptdesignziele des Clusters besteht darin, lineare Skalierbarkeit zu erreichen.
Der Redis-Cluster opfert eine gewisse Fehlertoleranz, um die Konsistenz sicherzustellen: Das System gewährleistet eine begrenzte Widerstandsfähigkeit gegen Netzwerkunterbrechungen (Netzaufteilung) und Knotenfehler (Knotenfehler). Behalten Sie die Datenkonsistenz so weit wie möglich bei unter der Prämisse der Stärke.
Der Cluster behandelt Knotenausfälle als einen der Sonderfälle einer Netzwerkunterbrechung.
Die Fehlertoleranzfunktion des Clusters wird durch die Verwendung von Knoten mit zwei Rollen erreicht: Masterknoten (Master) und Slaveknoten (Slave):
Der Masterknoten und Die Slave-Knoten verwenden genau die gleiche Serverimplementierung und ihre Funktionen sind genau die gleichen, aber der Slave-Knoten wird normalerweise nur verwendet, um den ausgefallenen Master-Knoten zu ersetzen.
Wenn Sie jedoch die Konsistenz von „Zuerst schreiben, später lesen“-Vorgängen (Lese-nach-Schreib-Konsistenz) nicht sicherstellen müssen, können Sie Slave-Knoten verwenden, um schreibgeschützte Abfragen auszuführen.
Redis Cluster implementiert eine Teilmenge von Funktionen
Redis Cluster implementiert alle Befehle zur Verarbeitung eines einzelnen Datenbankschlüssels in eigenständigem Redis.
Komplexe Berechnungsoperationen für mehrere Datenbankschlüssel, wie z. B. Vereinigungsoperationen und Sammlungsoperationen von Mengen, sind ebenfalls nicht implementiert. Diese Befehle, die theoretisch die Verwendung mehrerer Datenbankschlüssel von mehreren Knoten erfordern, sind ebenfalls nicht implementiert. Nicht implementiert.
In Zukunft können Benutzer möglicherweise den Befehl MIGRATE COPY verwenden, um schreibgeschützte Vorgänge für mehrere Datenbankschlüssel im Berechnungsknoten des Clusters durchzuführen, aber der Cluster selbst wird diese Anforderungen nicht umsetzen Mehrschlüsselbefehle zum Verschieben mehrerer Datenbankschlüssel um mehrere Knoten herum.
Der Redis-Cluster unterstützt nicht mehrere Datenbankfunktionen wie eigenständiges Redis. Der Cluster verwendet nur die Standarddatenbank Nr. 0 und kann den SELECT-Befehl nicht verwenden.
Clients und Server im Redis-Clusterprotokoll
Knoten im Redis-Cluster haben die folgenden Verantwortlichkeiten:
Halten von Schlüssel-Wert-Paaren Daten.
Zeichnen Sie den Status des Clusters auf, einschließlich der Zuordnung von Schlüsseln zu den richtigen Knoten.
Erkennen Sie automatisch andere Knoten, identifizieren Sie Knoten, die nicht ordnungsgemäß funktionieren, und wählen Sie bei Bedarf neue Master-Knoten aus Slave-Knoten aus.
Um die oben aufgeführten Aufgaben auszuführen, baut jeder Knoten im Cluster einen „Clusterbus“ mit anderen Knoten auf. Bei dieser Verbindung handelt es sich um eine TCP-Verbindung, die das Binärprotokoll verwendet.
Das Gossip-Protokoll wird zwischen Knoten verwendet, um die folgenden Aufgaben auszuführen:
Informationen über den Cluster weitergeben, um neue Knoten zu entdecken.
Senden Sie PING-Pakete an andere Knoten, um zu überprüfen, ob der Zielknoten ordnungsgemäß funktioniert.
Senden Sie Clusterinformationen, wenn bestimmte Ereignisse auftreten.
Darüber hinaus werden Clusterverbindungen auch genutzt, um Informationen im Cluster zu veröffentlichen oder zu abonnieren.
Da Clusterknoten keine Befehlsanfragen weiterleiten können, sollte der Client die Befehlsanforderung selbst an andere Knoten weiterleiten, wenn der Knoten einen Umleitungsfehler -MOVED oder -ASK zurückgibt.
Weil es dem Client freisteht, Befehlsanfragen an jeden Knoten im Cluster zu senden, und wenn nötig, kann er den Befehl basierend auf den durch den Steuerungsfehler bereitgestellten Informationen an den richtigen Knoten weiterleiten, also theoretisch , muss der Client keine Clusterstatusinformationen speichern.
Wenn der Client jedoch die Zuordnungsinformationen zwischen Schlüsseln und Knoten speichern kann, kann er die Anzahl möglicher Umleitungen effektiv reduzieren und so die Effizienz der Befehlsausführung verbessern.
Schlüsselverteilungsmodell
Der Schlüsselraum des Redis-Clusters ist in 16384 Slots unterteilt, und die maximale Anzahl von Knoten im Cluster beträgt ebenfalls 16384.
Die empfohlene maximale Anzahl von Knoten beträgt etwa 1000.
Jeder Masternode ist für die Verarbeitung eines Teils der 16384 Hash-Slots verantwortlich.
Wenn wir sagen, dass sich ein Cluster in einem „stabilen“ Zustand befindet, meinen wir, dass der Cluster keine Rekonfigurationsvorgänge ausführt und jeder Hash-Slot nur von einem Knoten verarbeitet wird.
Rekonfiguration bezieht sich auf das Verschieben bestimmter/bestimmter Slots von einem Knoten auf einen anderen.
Ein Master-Knoten kann eine beliebige Anzahl von Slave-Knoten haben. Diese Slave-Knoten werden verwendet, um den Master-Knoten zu ersetzen, wenn die Netzwerkverbindung unterbrochen wird oder der Knoten ausfällt.
Der folgende Algorithmus ist für die Zuordnung von Schlüsseln zu Slots verantwortlich:
HASH_SLOT = CRC16(key) mod 16384
Die folgenden Parameter werden vom Algorithmus verwendet:
Name des Algorithmus: XMODEM (auch bekannt als ZMODEM oder CRC-16/ACORN)
Länge des Ergebnisses: 16 Bits
Polynomzahl (Poly): 1021 (d. h. x16 + x12 + x5 + 1)
Initialisierungswert: 0000
Eingabebyte reflektieren: Falsch
Ausgabe-CRC reflektieren: Falsch
Xor-Konstante zur Ausgabe CRC: 0000
Die Ausgabe dieses Algorithmus für die Eingabe „123456789“: 31C3
Gegeben in Anhang A Implementierung des vom Cluster verwendeten CRC16-Algorithmus.
14 Bits der vom CRC16-Algorithmus erzeugten 16-Bit-Ausgabe werden verwendet.
In unseren Tests hat der CRC16-Algorithmus gute Arbeit geleistet und verschiedene Schlüsseltypen reibungslos auf 16384 Steckplätze verteilt.
Clusterknotenattribute
Jeder Knoten hat eine eindeutige ID im Cluster. Die ID ist eine 160-Bit-Zufallszahl, die aus /dev/urandom generiert wird wenn der Knoten zum ersten Mal gestartet wird.
Der Knoten speichert seine ID in der Konfigurationsdatei. Solange die Konfigurationsdatei nicht gelöscht wird, verwendet der Knoten immer diese ID.
Die Knoten-ID wird verwendet, um jeden Knoten im Cluster zu identifizieren. Ein Knoten kann seine IP- und Portnummer ändern, ohne die Knoten-ID zu ändern. Der Cluster kann Änderungen der IP-/Portnummern automatisch erkennen und diese Informationen über das Gossip-Protokoll an andere Knoten senden.
Das Folgende sind die zugehörigen Informationen, über die jeder Knoten verfügt, und der Knoten sendet diese Informationen an andere Knoten:
Die von ihm verwendete IP-Adresse und TCP-Portnummer Knoten.
Knotenflags.
Der Hash-Slot, für dessen Verarbeitung der Knoten verantwortlich ist.
Das letzte Mal, dass ein Knoten ein PING-Paket über eine Clusterverbindung gesendet hat.
Das letzte Mal, als der Knoten ein PONG-Paket als Antwort erhalten hat.
Der Zeitpunkt, zu dem der Cluster den Knoten als offline markiert.
Die Anzahl der Slave-Knoten dieses Knotens.
Wenn der Knoten ein Slave-Knoten ist, zeichnet er die Knoten-ID des Master-Knotens auf. Wenn es sich um einen Masterknoten handelt, lautet der Wert in der Spalte „Masterknoten-ID“ 0000000.
Ein Teil der oben genannten Informationen kann durch Senden des Befehls CLUSTER NODES an einen beliebigen Knoten im Cluster (entweder den Master-Knoten oder den Slave-Knoten) erhalten werden.
Das Folgende ist ein Beispiel für das Senden des Befehls CLUSTER NODES an den Masterknoten in einem Cluster, der aus drei Knoten besteht:
$ 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
In den drei oben aufgeführten Informationszeilen sind die Felder von links nach rechts: Knoten-ID, IP-Adresse und Portnummer, Flag, das letzte Mal, als PING gesendet wurde, das letzte Mal, als PONG empfangen wurde, der Verbindungsstatus , der Slot, für dessen Verarbeitung der Knoten verantwortlich ist.
Knoten-Handshake (implementiert)
Der Knoten akzeptiert immer die Verbindungsanfrage vom Cluster-Verbindungsport und antwortet auf das empfangene PING-Paket ein nicht vertrauenswürdiger Knoten.
Mit Ausnahme von PING lehnt der Knoten jedoch alle anderen Pakete ab, die nicht vom Clusterknoten stammen.
Damit ein Knoten erkennt, dass ein anderer Knoten zum selben Cluster gehört, gibt es nur zwei Methoden:
Ein Knoten kann eine MEET-Nachricht an einen anderen Knoten senden Der Knoten, der die Nachricht empfängt, erkennt den Knoten, der die Nachricht sendet, als Mitglied des Clusters. Ein Knoten sendet MEET-Informationen nur dann an einen anderen Knoten, wenn der Administrator ihm explizit den Befehl „CLUSTER MEET ip port“ sendet.
Wenn außerdem ein vertrauenswürdiger Knoten die Informationen eines Drittknotens an einen anderen Knoten weiterleitet, identifiziert der Knoten, der die Informationen empfängt, auch den Drittknoten als Mitglied des Clusters. Das heißt, wenn A B kennt, B C kennt und B Informationen über C an A weitergibt, erkennt A auch C als Mitglied des Clusters und versucht, eine Verbindung zu C herzustellen.
Das bedeutet, dass, wenn wir einem Cluster einen oder mehrere neue Knoten hinzufügen, dieser/diese neuen Knoten schließlich mit allen anderen Knoten verbunden werden, die sich bereits im Cluster befinden.
Das bedeutet, dass der Cluster automatisch andere Knoten erkennen kann, solange der Administrator die vertrauenswürdige Beziehung explizit mit dem Befehl CLUSTER MEET angibt.
Dieser Mechanismus zur Knotenidentifizierung macht den Cluster robuster, indem er unerwartete Kombinationen (Mischungen) verschiedener Redis-Cluster aufgrund von IP-Adressänderungen oder anderen Netzwerkereignissen verhindert.
Wenn die Netzwerkverbindung eines Knotens getrennt wird, stellt er aktiv eine Verbindung zu anderen bekannten Knoten her.
VERSCHOBEN
一个 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 。
Beachten Sie, dass selbst wenn ein Fehler auf dem Client auftritt und Steckplatz 8 vorzeitig Knoten B zugeordnet wird, der Client beim Senden einer Befehlsanforderung auf einen MOVED-Fehler stößt und sich umdreht, solange der Client den ASKING-Befehl nicht sendet zurück zum Knoten A.
Fehlertoleranz
Knotenfehlererkennung
Das Folgende ist die Implementierungsmethode der Knotenfehlererkennung:
Wenn ein Knoten einen PING-Befehl an einen anderen Knoten sendet, der Zielknoten jedoch innerhalb eines bestimmten Zeitlimits keine Antwort auf den PING-Befehl zurücksendet, markiert der Knoten, der den Befehl sendet, den Zielknoten als PFAIL (möglicher Fehler).
Das Zeitlimit für das Warten auf die Antwort des PING-Befehls wird als „Knoten-Timeout“ bezeichnet und ist eine knotenweise Einstellung.
Jedes Mal, wenn ein Knoten einen PING-Befehl an andere Knoten sendet, sendet er zufällig drei Informationen über die ihm bekannten Knoten. Eine der Informationen ist, ob der Knoten als PFAIL oder FAIL markiert wurde.
Wenn ein Knoten Informationen von anderen Knoten empfängt, zeichnet er die Knoten auf, die von anderen Knoten als ausgefallen markiert wurden. Dies wird als Fehlerbericht bezeichnet.
Wenn ein Knoten einen Knoten als PFAIL markiert hat und basierend auf dem expliziten Fehlerbericht, den der Knoten erhalten hat, die meisten anderen Masterknoten im Cluster ebenfalls davon ausgehen, dass der Knoten in einen fehlerhaften Zustand eingetreten ist, wird der Knoten den Status erhalten als FAIL markiert.
Sobald ein Knoten als FAIL markiert ist, wird die Information, dass der Knoten ausgefallen ist, an den gesamten Cluster gesendet und alle Knoten, die diese Informationen empfangen, markieren den ausgefallenen Knoten als FAIL.
Einfach ausgedrückt: Wenn ein Knoten einen anderen Knoten als ungültig markieren möchte, muss er zunächst andere Knoten nach ihrer Meinung fragen und die Zustimmung der Mehrheit der Masterknoten einholen.
Da abgelaufene Fehlerberichte entfernt werden, muss der Masterknoten, wenn er einen Knoten als FAIL markieren möchte, auf dem zuletzt empfangenen Fehlerbericht basieren.
In den folgenden zwei Situationen wird der FAIL-Status des Knotens entfernt:
Wenn der mit FAIL gekennzeichnete Knoten ein Slave-Knoten ist, dann, wenn der Knoten zurückkommt online wird die Markierung „FAIL“ entfernt.
Es macht keinen Sinn, den FAIL-Status des Slave-Knotens beizubehalten, da er keine Slots verarbeitet. Ob sich ein Slave-Knoten im FAIL-Status befindet, bestimmt, ob der Slave-Knoten bei Bedarf zum Master-Knoten hochgestuft werden kann.
Wenn ein Master-Knoten nach dem Vierfachen der Node-Timeout-Periode plus zehn Sekunden als FAIL markiert wurde, wurde der Failover-Vorgang für den Steckplatz des Master-Knotens nicht abgeschlossen und der Master-Knoten ist ausgefallen. Wenn er wieder online geht, Entfernen Sie die FAIL-Markierung auf diesem Knoten.
Im zweiten Fall, wenn das Failover fehlschlägt und der Masterknoten wieder online geht, verwendet der Cluster weiterhin den ursprünglichen Masterknoten, sodass kein Administratoreingriff erforderlich ist.
Cluster-Statuserkennung (teilweise implementiert)
Immer wenn eine Konfigurationsänderung im Cluster auftritt (es kann sich um eine Hash-Slot-Aktualisierung handeln oder ein Knoten geht in einen ausgefallenen Zustand über) , scannt jeder Knoten im Cluster die ihm bekannten Knoten.
Sobald die Konfiguration verarbeitet ist, geht der Cluster in einen der folgenden zwei Zustände über:
FEHLER: Der Cluster kann nicht ordnungsgemäß funktionieren. Wenn ein Knoten im Cluster in den Fehlerzustand übergeht, kann der Cluster keine Befehlsanfragen verarbeiten. Für jede Befehlsanfrage gibt der Clusterknoten eine Fehlerantwort zurück.
OK: Der Cluster funktioniert normal und keiner der Knoten, die für die Verarbeitung aller 16384 Slots verantwortlich sind, ist als FAIL markiert.
Das bedeutet, dass selbst wenn nur ein Teil der Hash-Slots im Cluster nicht verwendet wird, der gesamte Cluster die Verarbeitung aller Befehle einstellt.
Allerdings funktioniert der Cluster während des Zeitraums vom Problem eines Knotens bis zur Markierung als FAIL weiterhin normal, sodass der Cluster irgendwann möglicherweise immer noch nur 16384 Slots verarbeiten kann. Eine Teilmenge der Befehlsanfragen.
Im Folgenden sind zwei Situationen aufgeführt, in denen der Cluster in den FAIL-Status wechselt:
Mindestens ein Hash-Slot ist nicht verfügbar, da der Knoten, der für die Verarbeitung dieses Slots verantwortlich ist, in den FAIL-Status übergegangen ist Zustand.
Die meisten Masterknoten im Cluster sind offline gegangen. Wenn die meisten Masterknoten in den PFAIL-Status wechseln, wechselt auch der Cluster in den FAIL-Status.
Die zweite Prüfung ist notwendig, da eine Mehrheit der Masterknoten abstimmen muss, um einen Knoten vom PFAIL-Status in den FAIL-Status zu ändern Im Fehlerstatus gibt es keine Möglichkeit, einen Knoten nur durch einen oder zwei Knoten als FAIL-Status zu markieren.
Mit der zweiten Prüfbedingung kann der Cluster daher einen bestimmten Masterknoten ändern, ohne die Meinung dieser Masterknoten einzuholen, solange die meisten Masterknoten im Cluster in den Offline-Zustand wechseln. Es wird festgestellt, dass sich der Knoten im Status „FEHLER“ befindet, was dazu führt, dass der gesamte Cluster die Verarbeitung von Befehlsanforderungen stoppt.
Slave-Knotenwahl
一旦某个主节点进入 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; }
相关推荐:
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Wissens über die Redis-Cluster-Spezifikation. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!