Dieser Artikel führt Sie durch den Failover (Sentinel) in Redis. Ich hoffe, er wird Ihnen helfen!
Wenn zwei oder mehr Redis-Instanzen eine Master-Slave-Beziehung bilden, weist der von ihnen gebildete Cluster ein gewisses Maß an Hochverfügbarkeit auf: Wenn der Master ausfällt, kann der Slave zum neuen Master werden und externe Lese- und Schreibdienste bereitstellen. Dieser Betriebsmechanismus wird zu einem Failover. [Verwandte Empfehlungen: Redis-Video-Tutorial]
Wer wird also den Fehler des Masters entdecken und Failover-Entscheidungen treffen?
Eine Möglichkeit besteht darin, einen Daemo-Prozess zur Überwachung aller Master-Slave-Knoten aufrechtzuerhalten, wie in der folgenden Abbildung dargestellt:
In einem Redis-Cluster gibt es einen Master und zwei Slaves . Der Daemon ist jedoch ein einzelner Knoten und seine Verfügbarkeit kann nicht garantiert werden. Es müssen mehrere Daemons eingeführt werden, wie in der folgenden Abbildung dargestellt:
Mehrere Daemons lösen das Verfügbarkeitsproblem, es treten jedoch Konsistenzprobleme auf. Wie kann eine Einigung darüber erzielt werden, ob ein bestimmter Master verfügbar ist? Im obigen Bild sind beispielsweise die beiden Netzwerke Daemon1 und Master blockiert, aber die Verbindung zwischen Daemon und Master ist reibungslos. Muss der Masterknoten zu diesem Zeitpunkt ein Failover durchführen?
Redis‘ Sentinel bietet eine Reihe von Interaktionsmechanismen zwischen mehreren Daemons und wird zu einem Daemon-Cluster, der auch als Sentinel-Knoten bezeichnet wird. Wie in der Abbildung unten gezeigt:
Diese Knoten kommunizieren, wählen und verhandeln miteinander und zeigen Konsistenz bei der Fehlererkennung und der Failover-Entscheidung des Masterknotens.
Der Sentinel-Cluster überwacht eine beliebige Anzahl von Mastern und Slaves unter dem Master und rüstet den Offline-Master automatisch von einem Slave unter ihm auf einen neuen Master hoch, um weiterhin Befehlsanfragen zu verarbeiten.
Um einen Sentinel zu starten, können Sie den Befehl:
./redis-sentinel ../sentinel.conf
oder den Befehl:
./redis-server ../sentinel.conf --sentinel
verwenden. Wenn ein Sentinel startet, muss er die folgenden Schritte ausführen:
Initialisieren Sie den Server
Sentinel Essence Das Obige ist ein Redis-Server, der in einem speziellen Modus ausgeführt wird. Er führt andere Aufgaben aus als ein gewöhnlicher Redis-Server, und der Initialisierungsprozess ist nicht genau derselbe. Beispielsweise lädt die normale Redis-Serverinitialisierung RDB- oder AOF-Dateien, um Daten wiederherzustellen, Sentinel lädt sie jedoch nicht, wenn es gestartet wird, da Sentinel keine Datenbank verwendet.
Ersetzen Sie den von gewöhnlichen Redis-Servern verwendeten Code durch Sentinel-spezifische Codes.
Ersetzen Sie einige der von gewöhnlichen Redis-Servern verwendeten Codes durch Sentinel-spezifische Codes. Beispielsweise verwendet ein normaler Redis-Server server.c/redisCommandTable als Befehlstabelle des Servers:
truct redisCommand redisCommandTable[] = { {"module",moduleCommand,-2,"as",0,NULL,0,0,0,0,0}, {"get",getCommand,2,"rF",0,NULL,1,1,1,0,0}, {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0}, {"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0}, {"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0}, {"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0}, ..... {"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0}, {"unlink",unlinkCommand,-2,"wF",0,NULL,1,-1,1,0,0}, {"exists",existsCommand,-2,"rF",0,NULL,1,-1,1,0,0}, {"setbit",setbitCommand,4,"wm",0,NULL,1,1,1,0,0}, {"getbit",getbitCommand,3,"rF",0,NULL,1,1,1,0,0}, {"bitfield",bitfieldCommand,-2,"wm",0,NULL,1,1,1,0,0}, {"setrange",setrangeCommand,4,"wm",0,NULL,1,1,1,0,0}, {"getrange",getrangeCommand,4,"r",0,NULL,1,1,1,0,0}, {"substr",getrangeCommand,4,"r",0,NULL,1,1,1,0,0}, {"incr",incrCommand,2,"wmF",0,NULL,1,1,1,0,0}, {"decr",decrCommand,2,"wmF",0,NULL,1,1,1,0,0}, {"mget",mgetCommand,-2,"rF",0,NULL,1,-1,1,0,0}, {"rpush",rpushCommand,-3,"wmF",0,NULL,1,1,1,0,0}, {"lpush",lpushCommand,-3,"wmF",0,NULL,1,1,1,0,0} ...... }
Sentinel verwendet sentinel.c/sentinelcmds als Serverliste, wie unten gezeigt:
struct redisCommand sentinelcmds[] = { {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0}, {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0}, {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0}, {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0}, {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0}, {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0}, {"role",sentinelRoleCommand,1,"l",0,NULL,0,0,0,0,0}, {"client",clientCommand,-2,"rs",0,NULL,0,0,0,0,0}, {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0}, {"auth",authCommand,2,"sltF",0,NULL,0,0,0,0,0} }
Initializing Sentinel status
Der Server initialisiert eine sentinel.c/sentinelState-Struktur (speichert den gesamten Status im Zusammenhang mit Sentinel-Funktionen im Server).
struct sentinelState { char myid[CONFIG_RUN_ID_SIZE+1]; /* This sentinel ID. */ //当前纪元,用于实现故障转移 uint64_t current_epoch; /* Current epoch. */ //监视的主服务器 //字典的键是主服务器的名字 //字典的值则是一个指向sentinelRedisInstances结构的指针 dict *masters; /* Dictionary of master sentinelRedisInstances. Key is the instance name, value is the sentinelRedisInstance structure pointer. */ //是否进入tilt模式 int tilt; /* Are we in TILT mode? */ //目前正在执行的脚本数量 int running_scripts; /* Number of scripts in execution right now. */ //进入tilt模式的时间 mstime_t tilt_start_time; /* When TITL started. */ //最后一次执行时间处理器的时间 mstime_t previous_time; /* Last time we ran the time handler. */ // 一个FIFO队列,包含了所有需要执行的用户脚本 list *scripts_queue; /* Queue of user scripts to execute. */ char *announce_ip; /* IP addr that is gossiped to other sentinels if not NULL. */ int announce_port; /* Port that is gossiped to other sentinels if non zero. */ unsigned long simfailure_flags; /* Failures simulation. */ int deny_scripts_reconfig; /* Allow SENTINEL SET ... to change script paths at runtime? */ }
Initialisieren Sie die Überwachungs-Master-Serverliste von Sentinel basierend auf der angegebenen Konfigurationsdatei.
Die Initialisierung des Sentinel-Status löst die Initialisierung des Master-Wörterbuchs aus, und die Initialisierung des Master-Wörterbuchs basiert auf der geladenen Sentinel-Konfigurationsdatei fortfahren.
Der Schlüssel des Wörterbuchs ist der Name des überwachenden Hauptservers, und der Wert des Wörterbuchs ist die Struktur sentinel.c/sentinelRedisInstance, die dem überwachten Hauptserver entspricht.
Einige Attribute der sentinelRedisInstance-Struktur sind wie folgt:
typedef struct sentinelRedisInstance { //标识值,记录了实例的类型,以及该实例的当前状态 int flags; /* See SRI_... defines */ //实例的名字 //主服务器的名字由用户在配置文件中设置 //从服务器以及Sentinel的名字由Sentinel自动设置 //格式为ip:port,例如“127.0.0.1:26379” char *name; /* Master name from the point of view of this sentinel. */ //实例运行的ID char *runid; /* Run ID of this instance, or unique ID if is a Sentinel.*/ //配置纪元,用于实现故障转移 uint64_t config_epoch; /* Configuration epoch. */ //实例的地址 sentinelAddr *addr; /* Master host. */ //sentinel down-after-milliseconds选项设定的值 //实例无响应多少毫秒之后才会被判断为主观下线(subjectively down) mstime_t down_after_period; /* Consider it down after that period. */ //sentinel monitor <master-name> <ip> <redis-port> <quorum>选项中的quorum //判断这个实例为客观下线(objective down)所需的支持投票的数量 unsigned int quorum;/* Number of sentinels that need to agree on failure. */ //sentinel parallel-syncs <master-name> <numreplicas> 选项的numreplicas值 //在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量 int parallel_syncs; /* How many slaves to reconfigure at same time. */ //sentinel failover-timeout <master-name> <milliseconds>选项的值 //刷新故障迁移状态的最大时限 mstime_t failover_timeout; /* Max time to refresh failover state. */ }
Beim Starten von Sentinel wird beispielsweise die folgende Konfigurationsdatei konfiguriert:
# sentinel monitor <master-name> <ip> <redis-port> <quorum> sentinel monitor master1 127.0.0.1 6379 2 # sentinel down-after-milliseconds <master-name> <milliseconds> sentinel down-after-milliseconds master1 30000 # sentinel parallel-syncs <master-name> <numreplicas> sentinel parallel-syncs master1 1 # sentinel failover-timeout <master-name> <milliseconds> sentinel failover-timeout master1 900000
Dann erstellt Sentinel die Instanzstruktur wie unten gezeigt für den Hauptserver-Master1:
Sentinel-Status Und die Organisation des Master-Wörterbuchs ist wie folgt:
Erstellen Sie eine Netzwerkverbindung zum Hauptserver.
Erstellen Sie eine Netzwerkverbindung zum überwachten Hauptserver. Sentinel wird zum Client des Hauptservers und senden Sie Nachrichten an den Hauptserverbefehl und erhalten Sie Informationen aus Befehlsantworten.
Sentinel erstellt zwei asynchrone Netzwerkverbindungen zum Hauptserver:
Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的master和slave发送INFO命令。
通过master的回复可获取master本身信息,包括run_id域记录的服务器运行ID,以及role域记录的服务器角色。另外还会获取到master下的所有的从服务器信息,包括slave的ip地址和port端口号。Sentinel无需用户提供从服务器的地址信息,由master返回的slave的ip地址和port端口号,可以自动发现slave。
当Sentinel发现master有新的slave出现时,Sentinel会为这个新的slave创建相应的实例外,Sentinel还会创建到slave的命令连接和订阅连接。
根据slave的INFO命令的回复,Sentinel会提取如下信息:
1.slave的运行ID run_id
2.slave的角色role
3.master的ip地址和port端口
4.master和slave的连接状态master_link_status
5.slave的优先级slave_priority
6.slave的复制偏移量slave_repl_offset
Sentinel在默认情况下会以每两秒一次的频率,通过命令连接向所有被监视的master和slave的_sentinel_:hello频道发送一条信息
发送以下格式的命令:
PUBLISH _sentinel_:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"
以上命令相关参数意义:
参数 | 意义 |
---|---|
s_ip | Sentinel的ip地址 |
s_port | Sentinel的端口号 |
s_runid | Sentinel的运行ID |
s_runid | Sentinel的运行ID |
m_name | 主服务器的名字 |
m_ip | 主服务器的IP地址 |
m_port | 主服务器的端口号 |
m_epoch | 主服务器当前的配置纪元 |
命令如下所示:
SUBSCRIBE sentinel:hello
如上图所示,对于每个与Sentinel连接的服务器 ,Sentinel既可以通过命令连接向服务器频道_sentinel_:hello频道发送信息,又通过订阅连接从服务器的_sentinel_:hello频道接收信息。
相互连接的各个Sentinel可以进行信息交换。Sentinel为master创建的实例结构中的sentinels字典保存了除Sentinel本身之外,所有同样监视这个主服务器的其它Sentinel信息。
前面也讲到sentinel会为slave创建实例(在master实例的slaves字典中)。现在我们也知道通过sentinel相互信息交换,也创建了其它sentinel的实例(在master实例的sentinels字典中)。我们将一个sentinel中保存的实例结构大概情况理一下,如下图所示:
从上图可以看到slave和sentinel字典的键由其ip地址和port端口组成,格式为ip:port,其字典的值为其对应的sentinelRedisInstance实例。
主观不可用
默认情况下Sentinel会以每秒一次的频率向所有与它创建了命令连接的master(包括master、slave、其它Sentinel)发送PING命令,并通过实例返回的PING命令回复来判断实例是否在线。
PING命令回复分为下面两种情况:
有效回复:实例返回 +PONG、-LOADING、-MASTERDOWN三种回复的一种
无效回复:除上面有效回复外的其它回复或者在指定时限内没有任何返回
Sentinel配置文件中的设置down-after-milliseconds毫秒时效内(各个sentinel可能配置的不相同),连续向Sentinel返回无效回复,那么sentinel将此实例置为主观下线状态,在sentinel中维护的该实例flags属性中打开SRI_S_DOWN标识,例如master如下所示:
客观不可用
在sentinel发现主观不可用状态后,它会将“主观不可用状态”发给其它sentinel进行确认,当确认的sentinel节点数>=quorum,则判定该master为客观不可用,随后进入failover流程。
上面说到将主观不可用状态发给其它sentinel使用如下命令:
SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>
各个参数的意义如下:
接受到以上命令的sentinel会反回一条包含三个参数的Multi Bulk回复:
1)down_state> 目标sentinel对该master检查结果,1:master已下线 2:master未下线
2)leader_runid> 两种情况,*表示仅用于检测master下线状态 ,否则表示局部领头Sentinel的运行ID(选举领头Sentinel)
3)leader_epoch> 当leader_runid为时,leader_epoch始终为0。不为时则表示目标Sentinel的局部领头Sentinel的配置纪元(用于选举领头Sentinel)
其中节点数量限制quorum为sentinel配置文件中配置的
sentinel monitor <master-name> <ip> <redis-port> <quorum>
quorum选项,不同的sentinel配置的可能不相同。
当sentinel认为master为客观下线状态,则会将master属性中的flags的SRI_O_DOWN标识打开,例如master如下图所示:
Wenn ein Master ausfällt, können mehrere Sentinel-Knoten durch gleichzeitige Interaktion den „subjektiven Nichtverfügbarkeitszustand“ des anderen erkennen und bestätigen, gleichzeitig den „objektiven Nichtverfügbarkeitszustand“ erreichen und dies planen ein Failover einleiten. Am Ende kann es aber nur einen Sentinel-Knoten als Failover-Initiator geben, dann muss ein „Sentinel Leader“ gewählt werden und ein Sentinel Leader-Wahlprozess muss gestartet werden. Der Sentinel-Mechanismus von Redis verwendet etwas Ähnliches wie das Raft-Protokoll, um diesen Wahlalgorithmus zu implementieren:
1 Die Epochenvariable von sentinelState ähnelt dem Begriff (Wahlrunde) im Raft-Protokoll.
2. Jeder Sentinel-Knoten, der bestätigt, dass der Master „objektiv nicht verfügbar“ ist, sendet seine eigene Wahlanfrage an die Umgebung ;
3 Wenn jeder Sentinel-Knoten keine anderen Wahlanfragen erhalten hat, wird die Absicht auf den ersten Kandidaten-Sentinel gesetzt und darauf antworten (Wer zuerst kommt, mahlt zuerst); wenn die Absicht in dieser Runde geäußert wurde, werden andere Kandidaten abgelehnt und die bestehende Absicht wird beantwortet (wie oben für die drei Parameter erwähnt). Multi-Bulk-Antwort, down_state ist 1, Leader_runid ist die laufende ID des Quell-Sentinels, der die zum ersten Mal empfangene Wahlanfrage initiiert hat, Leader_epoch ist die Konfigurationsepoche des Quell-Sentinels, der die zum ersten Mal empfangene Wahlanfrage initiiert hat)
4 Jeder Initiierungsparameter If Der Sentinel-Knoten, der die Anfrage auswählt, erhält mehr als die Hälfte der Absichten, einem teilnehmenden Sentinel zuzustimmen (vielleicht sich selbst), dann wird der Sentinel als Anführer bestimmt. Wenn diese Runde lange genug dauert und kein Anführer ausgewählt wird, wird die nächste Runde gestartet
Leader Sentinel Nach der Bestätigung wähltLeader Sentinel nach bestimmten Regeln einen aus allen Slaves des Masters als neuen Master aus.
Failover-Failover
Nachdem der Sentinel-Anführer gewählt wurde, führt der Sentinel-Anführer ein Failover auf dem Offline-Master durch:aus allen Slaves des Offline-Masters aus, der in gutem Zustand ist, einen Slave mit vollständigen Daten
, und senden Sie dann den Befehl:Schauen wir uns an, wie der neue Master ausgewählt wird? Der Sentinel-Anführer speichert alle Offline-Slaves in einer Liste und filtert und filtert dann nach den folgenden Regeln: Der Standardwert ist 100. Je niedriger die Replikatpriorität, desto höher die Priorität. 0 ist eine besondere Priorität, was bedeutet, dass kein Upgrade auf Master möglich ist.
Wenn mehrere Slaves mit gleichen Prioritäten vorhanden sind, wird der Slave mit dem größten Kopierversatz ausgewählt(die Daten sind vollständiger)
Sentinel Leader sendet den SLAVEOF-Befehl (SLAVEOF
Legen Sie den alten Master als Slave des neuen Masters fest und überwachen Sie ihn weiterhin. Wenn er wieder online ist, führt Sentinel den Befehl aus, um ihn zum Slave des neuen Masters zu machen.
Zusammenfassung
Standardmäßig führt Sentinel alle zehn Sekunden Informationen zum Master und Slave aus um Master-Änderungsinformationen zu ermitteln und neue Slave-Knoten zu entdecken.
Standardmäßig sendet Sentinel alle zwei Sekunden über Befehlsverbindungen eine Nachricht an den _sentinel_:hello-Kanal aller überwachten Master und Slaves, um mit anderen Sentinels zu interagieren.Das obige ist der detaillierte Inhalt vonEine ausführliche Analyse des Sentinel-Failovers in Redis. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!