Heim >Datenbank >Redis >Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

青灯夜游
青灯夜游nach vorne
2022-01-17 10:07:032588Durchsuche

Was sind die Hochverfügbarkeitslösungen für Redis? Dieser Artikel stellt Ihnen die Hochverfügbarkeitslösungen in Redis vor. Ich hoffe, er ist hilfreich für Sie!

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Redis wird normalerweise nicht einzeln bereitgestellt, da es sonst keinen Single Point of Failure verursacht. Was sind also die Hochverfügbarkeitslösungen für Redis?

Master-Slave-Replikation

Benutzer können den SLAVEOF-Befehl oder die SLAVEOF-Konfiguration verwenden, um einen Server einen anderen Server replizieren zu lassen. Der replizierte Server wird als Master-Server bezeichnet, der replizierende Server als Slave-Server. Auf diese Weise fügen Sie den Schlüsselwert auf dem Master-Server hinzu und lesen ihn gleichzeitig auf dem Slave-Server. [Verwandte Empfehlungen: Redis-Video-Tutorial]

Der Kopiervorgang ist in zwei Schritte unterteilt: Synchronisierung und Befehlsweitergabe.

Synchronisierung

Durch die Synchronisierung wird der Datenbankstatus vom Server auf den aktuellen Datenbankstatus des Masterservers aktualisiert.

Wenn der Client den SLAVEOF-Befehl an den Slave-Server sendet, synchronisiert sich der Slave-Server SYNC命令 mit dem Master-Server. Die Schritte sind wie folgt:

  • Der Slave-Server sendet den SYNC-Befehl an den Master-Server.

  • Der Hauptserver, der den SYNC-Befehl empfängt, führt den BGSAVE-Befehl aus, generiert im Hintergrund eine RDB-Datei und verwendet einen Puffer, um alle von nun an ausgeführten Schreibbefehle aufzuzeichnen.

  • Nachdem der BGSAVE-Befehl des Master-Servers ausgeführt wurde, sendet der Master-Server die von BGSAVE generierte RDB-Datei an den Slave-Server. Der Slave-Server empfängt und lädt die RDB-Datei und aktualisiert den Datenbankstatus des Slave-Servers an den Master Server, wenn er den BGSAVE-Befehl ausführt.

  • Der Master-Server sendet alle Schreibbefehle im Puffer an den Slave-Server, und der Slave-Server führt diese Schreibbefehle aus und aktualisiert den Datenbankstatus auf den aktuellen Datenbankstatus von Der Master-Server.

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Befehlsweitergabe

Nach Abschluss des Synchronisierungsvorgangs ist der Datenbankstatus des Master-Servers und des Slave-Servers konsistent, aber nachdem der Master-Server den Client-Schreibbefehl empfangen hat, wird der Master -Slave-Datenbank Die Datenkonsistenz tritt erneut auf und die Datenbankkonsistenz wird durch Befehlsweitergabe erreicht.

Optimierung der PSYNC-Synchronisierung

Die Synchronisierung vor 2.8 ist jedes Mal eine vollständige Synchronisierung, und wenn der Server nur für eine Weile getrennt ist, besteht tatsächlich keine Notwendigkeit, die Synchronisierung von Anfang an zu starten. Sie müssen nur die Verbindung trennen und die Daten werden synchronisiert. Daher begann Version 2.8, PSYNC anstelle des SYNC-Befehls zu verwenden.

PSYNC ist in zwei Situationen unterteilt: vollständige Synchronisierung und teilweise Synchronisierung. Bei der vollständigen Synchronisierung handelt es sich um die Verarbeitung des anfänglichen Synchronisierungsstatus, während bei der teilweisen Synchronisierung die Situation der Trennung und Wiederverbindung behandelt werden soll.

Implementierung der teilweisen Synchronisierung

Bei der teilweisen Synchronisierung werden hauptsächlich die folgenden drei Teile verwendet:

  • Der Replikationsoffset des Masterservers und der Replikationsoffset des Slaveservers
  • Der Replikationsrückstandspuffer des Masterservers
  • Der Laufende ID des Servers

Replikationsoffset

Replikationsoffset des Masterservers: Jedes Mal, wenn der Masterserver N Datenbytes an den Slaveserver weitergibt, erhöht er seinen eigenen Replikationsoffset um +N Replikationsoffset des Slaveservers : Jedes Mal, wenn der Slave-Server N Bytes an vom Master-Server übertragenen Daten empfängt, erhöht er seinen Replikationsoffset um +N Wenn sich Master- und Slave-Server in einem konsistenten Zustand befinden, sind ihre Offsets immer gleich. Wenn die Offsets nicht gleich sind, befinden sie sich in einem inkonsistenten Zustand.

Kopierrückstandspuffer

Der Kopierrückstandspuffer ist eine vom Hauptserver verwaltete FIFO-Warteschlange. Die Standardgröße beträgt 1 MB. Wenn die maximale Länge erreicht ist, wird das erste in die Warteschlange gestellte Element ausgeworfen Weg zu den neu in die Warteschlange gestellten Elementen.
Wenn der Redis-Befehl weitergegeben wird, wird er nicht nur an den Slave-Server, sondern auch an den Replikations-Backlog-Puffer gesendet.

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Wenn der Slave-Server erneut eine Verbindung zum Master-Server herstellt, sendet der Slave-Server seinen Replikations-Offset-Offset über den PSYNC-Befehl an den Master-Server. Der Master-Server entscheidet basierend auf dem Replikations-Offset über die Verwendung einer teilweisen Synchronisierung oder einer vollständigen Synchronisierung. Wenn die Daten nach dem Offset-Offset noch in den Backlog-Puffer kopiert werden, wird eine teilweise Synchronisierung verwendet, andernfalls wird eine vollständige Synchronisierung verwendet.
(Das Buch sagt nicht, wie man das beurteilen soll. Ich schätze, es sollte der Master-Kopierversatz abzüglich des Slave-Kopierversatzes sein. Wenn er größer als 1 MB ist, bedeutet das, dass es Daten gibt, die sich nicht im Pufferrückstand befinden?)

Die laufende ID des Servers

Wenn der Server startet, generiert er ein 40-stelliges Zufallszeichen als laufende ID des Servers.

Wenn der Slave-Server zum ersten Mal auf den Master-Server repliziert, übermittelt der Master-Server seine laufende ID an den Slave-Server und der Slave-Server speichert diese laufende ID. Wenn die Verbindung zum Slave-Server getrennt und wieder hergestellt wird, wird die gespeicherte laufende ID an ihn gesendet. Wenn die vom Slave-Server gespeicherte laufende ID mit der laufenden ID des aktuellen Master-Servers übereinstimmt, wird versucht, eine teilweise Synchronisierung durchzuführen Wenn dies nicht der Fall ist, wird eine vollständige Synchronisierung durchgeführt.

Der Gesamtprozess von PSYNC

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Heartbeat-Erkennung

In der Befehlsweitergabephase sendet der Slave-Server den Befehl standardmäßig einmal pro Sekunde an den Master-Server:
REPLICONF ACK &lt ;replication_offset>REPLICONF ACK <replication_offset></replication_offset>
其中replication_offset就是从服务器当前的复制偏移量。 发送REPLICONF ACK命令对于主从服务器有三个作用:

  • 检测主从服务器的网络连接状态。

  • 辅助实现min-slaves选项。

  • 检测命令丢失。

检测主从服务器的网络连接状态

主从服务器可以通过发送和接收REPLICONF ACK命令来检查两者之间的网络连接是否正常:如果主服务器超过一秒钟没有收到从服务器发来的REPLICONF ACK命令,那么主服务器就知道主从之间出现问题了。

辅助实现min-slaves选项

redis的min-slaves-to-writemin-slaves-max-lagwobei replication_offset der aktuelle Replikationsoffset vom Server ist. Das Senden des REPLICONF ACK-Befehls hat drei Funktionen für die Master- und Slave-Server:

Ermitteln des Netzwerkverbindungsstatus der Master- und Slave-Server.

Hilfsimplementierung der Min-Slaves-Option.

Befehlsverlust erkennen.

Erkennen Sie den Netzwerkverbindungsstatus des Master-Slave-Servers

Der Master-Slave-Server kann überprüfen, ob die Netzwerkverbindung zwischen den beiden normal ist, indem er den REPLICONF ACK-Befehl sendet und empfängt: Wenn der Master-Server dies nicht tut Wenn Sie länger als eine Sekunde lang eine Nachricht vom Slave-Server erhalten. REPLICONF ACK-Befehl vom Server gesendet, weiß der Master-Server, dass ein Problem zwischen Master und Slave vorliegt.

Hilfsimplementierung der Min-Slaves-Option

Die Optionen min-slaves-to-write und min-slaves-max-lag von Redis können Master-Slave verhindern Der Server führt den Schreibbefehl auf unsichere Weise aus. Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

min-slaves-to-write 3
min-slaves-max-lag 10

Wenn die Konfiguration wie oben erfolgt, bedeutet dies, dass der Master-Server die Ausführung des Schreibbefehls verweigert, wenn die Anzahl der Slave-Server weniger als 3 beträgt oder die Verzögerung aller 3 Slave-Server größer oder gleich 10 Sekunden ist .

    Befehlsverlust erkennen
  • Wenn der vom Master-Server an den Slave-Server übertragene Schreibbefehl aufgrund eines Netzwerkfehlers auf halbem Weg verloren geht, sendet der Slave-Server den Befehl REPLICONF ACK an den Master-Server Ermitteln Sie den aktuellen Replikations-Offset des Slave-Servers. Wenn der Offset kleiner als sein eigener Offset ist, kann der Master-Server die fehlenden Daten vom Slave-Server im Replikationspuffer basierend auf dem Replikations-Offset des Slave-Servers finden, die Daten neu schreiben und senden es an den Slave-Server. Zusammenfassung der Master-Slave-Replikation Bei der Master-Slave-Replikation können der Master- und der Slave-Server auf zwei verschiedenen Maschinen bereitgestellt werden, sodass Sie manuell zum Slave-Server wechseln können, um den Dienst fortzusetzen, selbst wenn der Master-Server-Rechner hängen bleibt.
  • sentinel
  • Obwohl Master-Slave die Datensicherung implementiert, müssen Sie manuell vom Slave-Server zum Master-Server wechseln, wenn der Master-Server auflegt. Sentinel kann automatisch vom sekundären Server zum primären Server wechseln, wenn der primäre Server auflegt.

Das Sentinel-System kann alle Master- und Slave-Server überwachen, vorausgesetzt, Server1 ist jetzt offline. Wenn die Offline-Zeit von Server1 die vom Benutzer festgelegte Obergrenze der Offline-Zeit überschreitet, führt das Sentinel-System einen Failover von Server1 durch:

Zuerst wählt das Sentinel-System einen der Slave-Server unter Server1 aus und überträgt diesen ausgewählten Slave Server wird auf den neuen Primärserver aktualisiert.

Danach sendet das Sentinel-System neue Replikationsbefehle an alle Slave-Server unter Server1, sodass diese zu Slave-Servern des neuen Master-Servers werden können. Der Failover-Vorgang ist abgeschlossen, wenn alle Slave-Server auf dem neuen Master-Server repliziert haben.

Darüber hinaus überwacht Sentinel auch den Offline-Server1 und legt ihn, wenn er wieder online ist, als Slave-Server des neuen Master-Servers fest.

Initialisieren Sie den Sentinel-Status

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

struct sentinelState {
    char myid[CONFIG_RUN_ID_SIZE+1]; 
    // 当前纪元,用于实现故障转移
    uint64_t current_epoch;
    // 保存了所有被这个sentinel监视的主服务器
    // 字典的键是主服务器的名字
    // 字典的值是指向sentinelRedisInstance结构的指针
    dict *masters;
    // 是否进入了TILT模式
    int tilt;         
    // 目前正在执行的脚本数量
    int running_scripts;   
    // 进入TILT模式的时间
    mstime_t tilt_start_time;   
    // 最后一次执行时间处理器的时间
    mstime_t previous_time;     
    // 一个fifo队列,包含了所有需要执行的用户脚本
    list *scripts_queue;            
    char *announce_ip;  
    int announce_port; 
    unsigned long simfailure_flags; 
    int deny_scripts_reconfig;
    char *sentinel_auth_pass;   
    char *sentinel_auth_user;    
    int resolve_hostnames;      
    int announce_hostnames;     
} sentinel;

Initialisieren Sie das Masters-Attribut des Sentinel-Status
masters zeichnet die relevanten Informationen aller von Sentinel überwachten Master-Server auf, wo sich der Schlüssel des Wörterbuchs befindet der Name des überwachten Servers und der Wert ist die sentinelRedisInstance-Struktur, die dem überwachten Server entspricht. sentinelRedisInstance ist eine vom Sentinel-Server überwachte Instanz, bei der es sich um einen Master-Server, einen Slave-Server oder andere Sentinel-Instanzen handeln kann.

typedef struct sentinelRedisInstance {
    // 标识值,记录实例的类型,以及该实例的当前状态
    int flags;  
    // 实例的名字
    // 主服务器名字在配置文件中设置
    // 从服务器和sentinel名字由sentinel自动设置,格式是ip:port
    char *name; 
    // 运行id
    char *runid;   
    // 配置纪元,用于实现故障转移
    uint64_t config_epoch;  
    // 实例的地址
    sentinelAddr *addr; /* Master host. */
    // 实例无响应多少毫秒之后,判断为主观下线
    mstime_t down_after_period; 
    // 判断这个实例为客观下线所需的支持投票数量
    unsigned int quorum;
    // 执行故障转移,可以同时对新的主服务器进行同步的从服务器数量
    int parallel_syncs; 
    // 刷新故障迁移状态的最大时限
    mstime_t failover_timeout;  
    // 除了自己外,其他监视主服务器的sentinel
    // 键是sentinel的名字,格式是ip:port
    // 值是键对应的sentinel的实例结构
    dict *sentinels;  
    // ...
} sentinelRedisInstance;

🎜🎜Erstellen Sie eine Netzwerkverbindung zum Hauptserver. 🎜🎜🎜🎜Der letzte Schritt bei der Initialisierung von Sentinel besteht darin, eine Netzwerkverbindung zum überwachten Hauptserver herzustellen. 🎜🎜🎜🎜🎜🎜🎜🎜Befehlsverbindung🎜: Senden Sie gezielt Befehle an den Hauptserver und empfangen Sie Befehlsantworten. 🎜🎜Abonnementverbindung🎜: Wird speziell zum Abonnieren des _sentinel_:hello-Kanals des Hauptservers verwendet. 🎜

Informationen zum Hauptserver abrufen

Sentinel sendet standardmäßig alle 10 Sekunden den INFO-Befehl über die Befehlsverbindung an den überwachten Hauptserver und ruft über die Antwort die aktuellen Informationen des Hauptservers ab. Antworten Sie, um die folgenden Informationen zu erhalten.

  • Die run_id des Master-Servers
  • Die Informationen aller Slave-Server unter dem Master-Server.

Das Namenswörterbuch und das Runid-Feld unter sentinelRedisInstance können basierend auf diesen Informationen aktualisiert werden.

Informationen zum Slave-Server abrufen

Sentinel erstellt auch Befehlsverbindungen und Abonnementverbindungen zum Slave-Server.

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

sentinel sendet standardmäßig alle 10 Sekunden einen INFO-Befehl über die Befehlsverbindung an den Slave-Server und erhält über die Antwort die aktuellen Informationen des Slave-Servers. Die Antwort lautet wie folgt:

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

  • Die laufende ID des Slave-Servers
  • Die Rolle des Slave-Servers
  • Die IP und der Port des Master-Servers
  • Der Verbindungsstatus des Master-Servers „master_link_status“
  • Die Priorität des Slave-Servers.
  • Informationen an die Abonnementverbindungen der Master- und Slave-Server senden

Standardmäßig sendet Sentinel alle 2 Sekunden Befehle an die überwachten Master- und Slave-Server.

s_ip:sentinels IP-Adresse

s_port:sentinels Portnummer

s_runid:sentinels laufende IDLassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!s_epoch code>: Aktuelle Konfigurationsepoche von Sentinel

m_name: Der Name des Hauptservers

m_ip: Die IP-Adresse des Hauptservers s_ip:sentinel的ip地址
s_port:sentinel的端口号
s_runid:sentinel的运行id
s_epoch:sentinel当前的配置纪元
m_name:主服务器的名字
m_ip:主服务器的ip地址
m_port:主服务器的端口号
m_epoch:主服务器当前的配置纪元
向sentinel_:hello频道发送信息,也会被监视同一个服务器的其他sentinel监听到(包括自己)。

创建连向其他sentinel的命令连接

sentinel之间会互相创建命令连接。监视同一个嘱咐其的多个sentinel将形成相互连接的网络。

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

sentinel之间不会创建订阅连接。

检测主观下线状态

sentinel会每秒一次向所有与它创建了命令连接的实例(主服务器、从服务器、其他sentinel)发送ping命令,通过实例的回复来判断实例是否在线。
有效回复:实例返回+PONG、-LOADING、-MASTERDOWN其中一种。
无效回复:以上三种回复之外的其他回复,或者指定时长内没回复。
某个实例在down-after-milliseconds毫秒内,连续向sentinel返回无效回复。那么sentinel就会修改这个实例对应的实例结构,在结构的flags属性中打开SRI_S_DOWN标识,标识该实例进入主观下线状态。(down-after-milliseconds可以在sentinel的配置文件中配置)

检测客观下线状态

当sentinel将一个主服务器判断为主观下线后,为了确认这个主服务器是否真的下线,还会想其他同样监视这个主服务器的其他sentinel询问,看其他sentinel是否也认为该主服务器下线了。超过一定数量就将主服务器判断为客观下线。

询问其他sentinel是否同意该服务器下线

SENTINEL is-master-down-by-addr <ip><port><current_epoch><runid></runid></current_epoch></port></ip>m_port: Die Portnummer des Hauptservers

m_epoch: Die aktuelle Konfigurationsepoche des Hauptservers
Das Senden von Informationen an den sentinel_:hello-Kanal wird auch von anderen Sentinels überwacht, die denselben Server überwachen (einschließlich Ihnen selbst).

Befehlsverbindungen zu anderen Sentinels erstellen

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Sentinels erstellen Befehlsverbindungen untereinander. Mehrere Wächter, die denselben Befehl überwachen, bilden ein miteinander verbundenes Netzwerk.

Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Es werden keine Abonnementverbindungen zwischen Sentinels erstellt.

10-Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Erkennen Sie den subjektiven Offline-Status

Sentinel sendet einmal pro Sekunde einen Ping-Befehl an alle Instanzen (Master-Server, Slave-Server, andere Sentinel), mit denen er eine Befehlsverbindung hergestellt hat, und beurteilt die Instanz anhand des Antwort der Instanz Ist es online? Gültige Antwort

: Die Instanz gibt eines von +PONG, -LOADING und -MASTERDOWN zurück. 🎜🎜Ungültige Antwort🎜: Andere Antworten als die oben genannten drei Antworttypen oder keine Antwort innerhalb der angegebenen Zeit. 🎜Eine Instanz gibt innerhalb von down-after-milliseconds Millisekunden kontinuierlich ungültige Antworten an Sentinel zurück. Anschließend ändert Sentinel die dieser Instanz entsprechende Instanzstruktur und aktiviert das Flag SRI_S_DOWN im Flags-Attribut der Struktur, um anzuzeigen, dass die Instanz in den subjektiven Offline-Status eingetreten ist. (Abschaltzeit nach Millisekunden kann in der Sentinel-Konfigurationsdatei konfiguriert werden) 🎜🎜🎜🎜Ermitteln Sie den objektiven Offline-Status🎜🎜🎜🎜🎜Wenn Sentinel feststellt, dass ein Hauptserver subjektiv offline ist, um zu bestätigen, ob der Hauptserver wirklich offline ist Wenn es offline geht, werden auch andere Sentinels, die ebenfalls den Hauptserver überwachen, gefragt, ob andere Sentinels ebenfalls der Meinung sind, dass der Hauptserver offline ist. Wenn die Anzahl eine bestimmte Anzahl überschreitet, wird davon ausgegangen, dass der Hauptserver objektiv offline ist. 🎜🎜🎜🎜Fragen Sie andere Sentinels, ob sie damit einverstanden sind, dass der Server offline ist.🎜🎜🎜SENTINEL is-master-down-by-addr <ip><port><current_epoch><runid></runid></current_epoch></port></ip>🎜 🎜🎜Fragen Sie über den Befehl SENTINEL is-master-down-by-addr. Die Bedeutung der Parameter ist wie folgt: 🎜🎜🎜🎜🎜🎜🎜Empfangen Sie den Befehl SENTINEL is-master-down-by-addr 🎜🎜 🎜Anderer Sentinel empfängt den SENTINEL is- Nachdem der Befehl „master-down-by-addr“ ausgeführt wurde, prüft er anhand der IP und des Ports des Master-Servers, ob der Master-Server offline ist, und sendet dann eine Multi-Bulk-Antwort mit drei zurück Parameter. 🎜🎜🎜🎜🎜sentinel zählt die Anzahl der anderen Sentinels, die zustimmen, dass der Hauptserver offline war. Wenn die konfigurierte Anzahl erreicht ist, wird das SRI_O_DOWN-Flag des Flags-Attributs des Hauptservers aktiviert, was anzeigt, dass der Hauptserver offline war in einen objektiven Offline-Zustand eingetreten. 🎜🎜🎜🎜Wählen Sie den Anführerwächter🎜🎜🎜

Wenn festgestellt wird, dass ein Master-Server objektiv offline ist, verhandelt jeder Sentinel, der den Offline-Master-Server überwacht, über die Wahl eines neuen Leit-Sentinels, und dieser Sentinel führt Failover-Vorgänge durch.

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

Nachdem bestätigt wurde, dass der Master-Server in den Ziel-Offline-Status eingetreten ist, wird der Befehl SENTINEL is-master-down-by-addr erneut gesendet, um den Anführer-Sentinel zu wählen.

Wahlregeln

  • Jeder von mehreren Online-Sentinels, die denselben Master-Server überwachen, kann zum Anführer-Sentinel werden.
  • Nach jeder Leader-Sentinel-Wahl werden die Konfigurationsepochenwerte aller Sentinels unabhängig davon, ob die Wahl erfolgreich ist oder nicht, von selbst erhöht. (Eine Konfigurationsepoche ist eigentlich ein Zähler)
  • In einer Konfigurationsepoche haben alle Sentinels die Möglichkeit, einen bestimmten Sentinel als lokalen Sentinel festzulegen. Sobald er in dieser Konfigurationsepoche festgelegt ist, kann er nicht mehr geändert werden.
  • Alle Sentinels, die feststellen, dass der Master-Server objektiv offline ist, werden andere Sentinels bitten, sich selbst als lokal führende Sentinels festzulegen, d. h. sie senden den Befehl SENTINEL is-master-down-by-addr, um zu versuchen, andere Sentinels zuzulassen setzen sich als örtlicher Leitwächter ein.
  • Wenn ein Sentinel den Befehl SENTINEL is-master-down-by-addr an einen anderen Sentinel sendet und der Wert des Runid-Parameters nicht *, sondern die Runid des Quell-Sentinels ist, bedeutet dies dass der Zielwächter erforderlich ist. Legen Sie sich selbst als Hauptwächter fest. SENTINEL is-master-down-by-addr命令时,如果runid参数的值不是*,而是源sentinel的runid,就表示要目标sentinel将自己设置成领头sentinel。
  • sentinel设置局部领头的规则是先到先得
  • Die Regel für die Festlegung des lokalen Anführers lautet: Wer zuerst kommt, mahlt zuerst Nachdem der erste Sentinel als lokaler Anführer festgelegt wurde, werden alle anderen Anfragen abgelehnt.
  • Nach dem Empfang eines SENTINEL-Befehls „is-master-down-by-addr“ sendet der Ziel-Sentinel eine Befehlsantwort an den Quell-Sentinel zurück. Die Parameter „leader_runid“ und „leader_epoch“ in der Antwort zeichnen jeweils die Runid und die Konfigurationsepoche des lokalen Leader-Sentinels des Ziel-Sentinels auf.
  • Nachdem der Quell-Sentinel die Antwort erhalten hat, vergleicht er, ob die zurückgegebene Konfigurationsepoche mit seiner eigenen Konfigurationsepoche übereinstimmt. Wenn ja, vergleicht er weiterhin, ob die Runid des zurückgegebenen lokalen führenden Sentinels mit seiner eigenen übereinstimmt runid. Wenn sie konsistent sind, bedeutet dies, dass der Ziel-Sentinel seine eigene Runid ändert. Als lokaler führender Sentinel eingerichtet.
  • Wenn ein Sentinel von mehr als der Hälfte der Sentinels als lokal führender Sentinel festgelegt wird, wird er zum führenden Sentinel.
  • Der führende Sentinel benötigt die Unterstützung von mehr als der Hälfte und kann in jeder Konfigurationsepoche nur einmal festgelegt werden. Dann erscheint in einer Konfigurationsepoche nur ein führendes Sentinel.
  • Wenn innerhalb eines bestimmten Zeitlimits jeder Sentinel ausgewählt wird der führende Wächter (keine Person erhält mehr als die Hälfte der Stimmen), dann wird jeder Wächter nach einer gewissen Zeit wiedergewählt, bis der führende Wächter gewählt ist

Failover

Failover umfasst Folgendes Drei Schritte:
  • Nachdem es offline ist, wählen Sie unter allen Slave-Servern unter dem Master-Server einen Slave-Server aus und konvertieren Sie ihn in den Master-Server.
  • Lassen Sie alle Slave-Server unter dem Offline-Master-Server auf den neuen Master-Server kopieren.
  • Legen Sie den Offline-Master-Server als Slave-Server des neuen Servers fest. Nachdem der alte Master-Server wieder online ist, wird er zum Slave-Server des neuen Master-Servers.

Wählen Sie einen neuen Master-Server aus.

Wählen Sie einen Slave-Server aus allen Slave-Servern unter dem Offline-Master-Server aus und senden Sie den Befehl SLAVEOF no one an den Slave-Server, um den Slave-Server zu konvertieren. Werden Sie zum Master Server.

Regeln für die Auswahl eines neuen Master-Servers

Der führende Wächter speichert alle Slave-Server des Offline-Master-Servers in einer Liste und filtert diese Liste dann, um einen neuen Master-Server auszuwählen.
  • Löschen Sie alle Slave-Server in der Liste, die offline oder nicht verbunden sind.
  • Löschen Sie alle Slave-Server in der Liste, die in den letzten fünf Sekunden nicht auf den INFO-Befehl des führenden Sentinels geantwortet haben.
  • Löschen Sie alle Server, die länger als nach Millisekunden von Offline-Servern getrennt wurden * 10 Millisekunden
  • Sortieren Sie dann die verbleibenden Slave-Server in der Liste nach der Priorität des Slave-Servers und wählen Sie den Server mit der höchsten Priorität aus.
  • Wenn es mehrere Slave-Server mit derselben höchsten Priorität gibt, sortieren Sie nach dem Replikationsoffset und wählen Sie den Slave-Server mit dem größten Offset aus (der größte Replikationsoffset bedeutet auch, dass die gespeicherten Daten die neuesten sind)
  • Wenn der Replikationsoffset gleich ist, sortieren Sie nach der Runid und wählen Sie den Slave-Server mit der kleinsten Runid aus.

Nachdem der Befehl „slaveof no one“ gesendet wurde, sendet der führende Sentinel einmal alle Informationen an den aktualisierten Slave-Server Wenn sich beim zweiten Befehl (normalerweise alle 10 Sekunden) die zurückgegebene Antwortrolle vom ursprünglichen Slave zum Master ändert, weiß der führende Sentinel, dass der Slave-Server zum Master-Server aktualisiert wurde.

Ändern Sie das Replikationsziel des Slave-Servers

🎜

通过SLAVEOF命令来使从服务器复制新的主服务器。当sentinel监测到旧的主服务器重新上线后,也会发送SLAVEOF命令使它成为新的主服务器的从服务器。

sentinel总结

sentinel其实就是一个监控系统,,而sentinel监测到主服务器下线后,可以通过选举机制选出一个领头的sentinel,然后由这个领头的sentinel将下线主服务器下的从服务器挑选一个切换成主服务器,而不用人工手动切换。

集群

哨兵模式虽然做到了主从自动切换,但是还是只有一台主服务器进行写操作(当然哨兵模式也可以监视多个主服务器,但需要客户端自己实现负载均衡)。官方也提供了自己的方式实现集群。

节点

每个redis服务实例就是一个节点,多个连接的节点组成一个集群。

CLUSTER MEET <ip><port></port></ip>

向另一个节点发送CLUSTER MEET命令,可以让节点与目标节点进行握手,握手成功就能将该节点加入到当前集群。

启动节点

redis服务器启动时会根据cluster-enabled配置选项是否为yes来决定是否开启服务器集群模式。

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

集群数据结构

每个节点都会使用一个clusterNode结构记录自己的状态,并为集群中其他节点都创建一个相应的clusterNode结构,记录其他节点状态。

typedef struct clusterNode {
    // 创建节点的时间
    mstime_t ctime; 
    // 节点的名称
    char name[CLUSTER_NAMELEN];
    // 节点标识
    // 各种不同的标识值记录节点的角色(比如主节点或从节点)
    // 以及节点目前所处的状态(在线或者下线)
    int flags;     
    // 节点当前的配置纪元,用于实现故障转移
    uint64_t configEpoch;
    // 节点的ip地址
    char ip[NET_IP_STR_LEN];  
    // 保存建立连接节点的有关信息
    clusterLink *link;          
    
    list *fail_reports;  
    // ...
} clusterNode;

clusterLink保存着连接节点所需的相关信息

typedef struct clusterLink {
    // ...
    // 连接的创建时间
    mstime_t ctime;           
    // 与这个连接相关联的节点,没有就为null
    struct clusterNode *node;   
    // ...
} clusterLink;

每个节点还保存着一个clusterState结构,它记录了在当前节点视角下,集群目前所处的状态,例如集群在线还是下线,集群包含多少个节点等等。

typedef struct clusterState {
    // 指向当前节点clusterNode的指针
    clusterNode *myself;  
    // 集群当前的配置纪元,用于实现故障转移
    uint64_t currentEpoch;
    // 集群当前的状态,上线或者下线
    int state;           
    // 集群中至少处理一个槽的节点数量
    int size;      
    // 集群节点的名单(包括myself节点)
    // 字典的键是节点的名字,字典的值为节点对应的clusterNode结构
    dict *nodes; 
} clusterState;

CLUSTER MEET 命令的实现

CLUSTER MEET <ip><port></port></ip>

  • 节点 A 会为节点 B 创建一个clusterNode结构,并将该结构添加到自己的clusterState.nodes 字典里面。

  • 之后,节点 A 将根据 CLUSTER MEET 命令给定的 IP 地址和端口号,向节点 B 发送一条 MEET 消息。

  • 如果一切顺利,节点 B 将接收到节点 A 发送的 MEET 消息,节点 B 会为节点 A 创建一个clusterNode结构,并将该结构添加到自己的clusterState.nodes字典里面。

  • 之后,节点 B 将向节点 A 返回一条 PONG 消息。

  • 如果一切顺利,节点 A 将接收到节点 B 返回的 PONG 消息,通过这条 PONG 消息节点 A 可以知道节点 B 已经成功地接收到了自己发送的 MEET 消息。

  • 之后,节点 A 将向节点 B 返回一条 PING 消息。

  • 如果一切顺利,节点B将接收到节点A返回的PING消息,通过这条PING消息节点B知道节点A已经成功接收到自己返回的PONG消息,握手完成。

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

槽指派

集群的整个数据库被分为16384个槽,每个键都属于16384个槽的其中一个,集群中每个节点处理0个或16384个槽。当所有的槽都有节点在处理时,集群处于上线状态,否则就是下线状态。

CLUSTER ADDSLOTS

CLUSTER ADDSLOTS <slot>...</slot>
通过CLUSTER ADDSLOTS命令可以将指定槽指派给当前节点负责,例如:CLUSTER ADDSLOTS 0 1 2 3 4 可以将0至4的槽指派给当前节点

记录节点的槽指派信息

clusterNode结构的slots属性和numslot属性记录了节点负责处理哪些槽:

typedef struct clusterNode {
         
    unsigned char slots[CLUSTER_SLOTS/8];
    
    int numslots;
    // ...
} clusterNode;

slots:是一个二进制数组,一共包含16384个二进制位。当二进制位的值是1,代表节点负责处理该槽,如果是0,代表节点不处理该槽numslots:numslots属性则记录节点负责处理槽的数量,也就是slots中值为1的二进制位的数量。

传播节点的槽指派信息

节点除了会将自己负责的槽记录在clusterNode中,还会将slots数组发送给集群中的其他节点,以此告知其他节点自己目前负责处理哪些槽。

typedef struct clusterState {
    clusterNode *slots[CLUSTER_SLOTS];
} clusterState;

slots包含16384个项,每一个数组项都是指向clusterNode的指针,表示被指派给该节点,如果未指派给任何节点,那么指针指向NULL。

CLUSTER ADDSLOTS命令的实现

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

在集群中执行命令

客户端向节点发送与数据库有关的命令时,接收命令的节点会计算出命令要处理的数据库键属于哪个槽,并检查该槽是否指派给了自己。
如果指派给了自己,那么该节点直接执行该命令。如果没有,那么该节点会向客户端返回一个MOCED的错误,指引客户端转向正确的节点,并再次发送执行的命令。

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

计算键属于那个槽

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

CRC16(key)是计算出键key的CRC16的校验和,而 & 16383就是取余,算出0-16383之间的整数作为键的槽号。

判断槽是否由当前节点负责处理

计算出键所属的槽号i后,节点就能判断该槽号是否由自己处理。
如果clusterState.slots[i]等于如果clusterState.myself,那么由自己负责该节点可以直接执行命令。
如果不相等,那么可以获取clusterState.slots[i]指向如果clusterNode的ip和端口,向客户端返回MOVED错误,指引客户端转向负责该槽的节点。

集群模式下不会打印MOVED错误,而是直接自动转向。

重新分片

redis集群重新分配可以将任意数量已经指派给某个节点的槽改为指派给另一个节点,相关槽所属的键值对也会从源节点移动到目标节点。
重新分片操作是在线进行的,在重新分片的过程中,集群不用下线,源节点和目标节点都可以继续处理命令请求。 redis集群的重新分片操作是由redis-trib负责执行。重新分片执行步骤如下:

  • redis-trib对目标节点发送CLUSTER SETSLOT <slot> IMPORTING <source_id></source_id></slot>命令,让目标节点准备好从源节点导入槽slot的键值对。

  • redis-trib对源节点发送CLUSTER SETSLOT <slot> MIGRTING <target_id></target_id></slot>命令,让源节点准备好将属于槽slot的键值对迁移至目标节点。

  • redis-trib向源节点发送CLUSTER GETKEYSINSLOT <slot> <count></count></slot>命令,获取最多count个属于槽的键值对的键名称。

  • 对于步骤3获取的每个键名,redis-trib都向源节点发送一个MIGRTING <target_ip> <target_port> <key_name> 0 <timeout></timeout></key_name></target_port></target_ip>命令,将被选中的键值对从源节点迁移至目标节点。

  • 重复执行步骤3和步骤4,直到源节点保存的所以属于槽slot的键值对都被迁移至目标节点。

  • redis-trib向集群中任何一个节点发送CLUSTER SETSLOT <slot> NODE <target_id></target_id></slot>命令,将槽指派给目标节点。这一信息最终会通过消息发送至整个集群。

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

CLUSTER SETSLOT IMPORTING 命令实现

typedef struct clusterState {
    // ...
    clusterNode *importing_slots_from[CLUSTER_SLOTS];

} clusterState;

importing_slots_from记录了当前节点正在从其他节点导入的槽。importing_slots_from[i]不为null,则指向CLUSTER SETSLOT <slot> IMPORTING <source_id></source_id></slot>命令,所代表的clusterNode结构。

CLUSTER SETSLOT MIGRTING 命令实现

typedef struct clusterState {
    // ...
    clusterNode *migrating_slots_to[CLUSTER_SLOTS];

} clusterState;

migrating_slots_to记录了当前节点正在迁移至其他节点的槽。migrating_slots_to[i]不为null,则指向迁移至目标节点所代表的clusterNode结构。

ASK错误

在重新分片期间,源节点向目标节点迁移槽的过程中,可能属于这个槽的一部分键值对一部分保存在源节点当中,而另一部分保存在目标节点当中。
客户端向源节点发送一个与数据库键有关的命令,恰好这个槽正在被迁移。
源节点现在自己的数据库中查找指定的键,如果找到,直接执行。
如果没有找到,节点会检查migrating_slots_to[i]查看键是否正在迁移,如果在迁移就返回一个ask错误,引导客户端转向目标节点。

ASKING

客户端收到ask错误之后,会先执行ASKING命令,再向目标节点发送命令。ASKING命令就是打开发送该命令的客户端的REDIS_ASKING标识。一般来说客户端发送的键如果不属于自己负责会返回MOVED错误(槽只迁移部分,这时槽还不属于目标节点负责),但还会检查importing_slots_from[i],如果显示节点正在导入槽i,并且发送命令的客户端带有REDIS_ASKING标识,那么它就会破例执行一次该命令。

1Lassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!

集群的故障转移

集群的故障转移效果和哨兵模式类似,也是将从节点升级成主节点。旧的主节点重新上线后将会成为新主节点的从节点。

故障检测

集群中每个节点会定期的向集群中其他节点发送PING消息,检测对方是否在线,如果指定时间内没有收到PONG消息,那么就将该节点标记为疑似下线。clusterState.nodes字典中找到该节点的clusterNode结构,将flags属性修改成REDIS_NODE_PFAIL标识。
集群中各个节点会互相发送消息来交换集群中各个节点的状态,例如:主节点A得知主节点B认为主节点C进入了疑似下线状态,主节点A会在clusterState.nodes字典中找到节点C的clusterNode结构,并将主节点B的下线报告添加到clusterNode结构的fail_reports链表当中。
每一个下线报告由一个clusterNodeFailReport结构表示

typedef struct clusterNodeFailReport {
    struct clusterNode *node; 
    // 最后一次收到下线报告的时间
    mstime_t time;            
} clusterNodeFailReport;

如果一个集群当中,半数以上负责处理槽的主节点都将某个主节点X报告为疑似下线。那么这个主节点X将被标记为已下线。将主节点X标记成已下线的节点会向集群广播一条关于主节点X的FAIL消息。所有收到这条FAIL消息的节点都会将主节点X标记成已下线。

故障转移

当一个从节点发现自己正在复制的主节点进入了已下线状态,从节点将开始对下线主节点进行故障转移。

  • 复制下线主节点的所有从节点,会有一个主节点被选中。

  • 被选中的从节点会执行SLAVEOF no one 命令,成为新的主节点。

  • 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己。

  • 新的主节点向集群广播一条PONG消息,这条PONG消息可以让集群中的其他节点立即知道这个节点已经由从节点变成主节点。这个主节点已经接管了已下线节点负责处理的槽。

  • 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。

选举新的主节点

新的主节点通过选举产生

  • 集群的配置纪元是一个自增计数器,它的初始值为0。

  • 当集群的某个节点开始一次故障转移操作,集群的配置纪元的值加1。

  • 对于每个配置纪元,集群里每个负责处理槽的主节点都有一次投票的机会,第一个想主节点要求投票的从节点将获得主节点的投票。

  • 当从节点发现自己正在复制的主节点进入已下线状态时,从节点会向集群广播一条CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST消息,要求所有收到这条消息,并具有投票权的主节点向这个从节点投票。

  • 如果一个主节点具有投票权(它正在负责处理槽),并且这个主节点尚未投票给其他从节点,那么主节点将向要求投票的从节点返回一条CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示这个主节点支持从节点成为新的主节点。

  • 每个参与选举的从节点都会接收CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,并根据自己收到了多少条这种消息来统计自己获得了多少主节点的支持。

  • 如果集群里有 N 个具有投票权的主节点,那么当一个从节点收集到大于等于 N / 2 + l 张支持票时,这个从节点就会当选为新的主节点。

  • 因为在每一个配置纪元里面,每个具有投票权的主节点只能投一次票,所以如果有 N 个主节点进行投票,那么具有大于等于 N / 2 + l 张支持票的从节点只会有一个,这确保了新的主节点只会有一个。

  • 如果在一个配置纪元里面没有从节点能收集到足够多的支持票,那么集群进人一个新的配置纪元,并再次进行选举,直到选出新的主节点为止。

主节点选举的过程和选举领头sentinel的过程非常相似。

数据丢失

主从复制数据丢失

主从复制之间是异步执行的,有可能master的部分数据还没来得及同步到从数据库,然后master就挂了,这时这部分未同步的数据就丢失了。

脑裂

脑裂就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着。此时哨兵可能就会认为master 宕机了,然后开启选举,将其他slave切换成了master,这个时候,集群里面就会有2个master,也就是所谓的脑裂。
此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续向旧master的写数据。
master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据将会清空,重新从新的master复制数据,导致数据丢失。

减少数据丢失的配置

min-slaves-to-writ 1
min-slaves-max-lag 10

上述配置表示,如果至少有1个从服务器超过10秒没有给自己ack消息,那么master不再执行写请求。

主从数据不一致

当从数据库因为网络原因或者执行复杂度高命令阻塞导致滞后执行同步命令,导致数据同步延迟,造成了主从数据库不一致。

都看到这了,点个赞再走了吧:)

更多编程相关知识,请访问:编程入门!!

Das obige ist der detaillierte Inhalt vonLassen Sie uns über die Hochverfügbarkeitslösungen in Redis sprechen!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen