Maison > Article > base de données > Une analyse approfondie du basculement sentinelle dans Redis
Cet article vous guidera à travers le basculement (sentinel) dans Redis, j'espère qu'il vous sera utile !
Lorsque deux instances Redis ou plus forment une relation maître-veille, le cluster qu'elles forment a un certain degré de haute disponibilité : lorsque le maître tombe en panne, l'esclave peut devenir le nouveau maître pour fournir des services externes de lecture et d'écriture. Ce mécanisme de fonctionnement devient un basculement. [Recommandations associées : Tutoriel vidéo Redis]
Alors, qui découvrira la faute du maître et prendra les décisions de basculement ?
Une solution consiste à maintenir un processus démon pour surveiller tous les nœuds maître-esclave, comme indiqué dans la figure ci-dessous :
Il y a un maître et deux esclaves dans un cluster Redis. Cependant, le démon est un nœud unique et sa disponibilité ne peut être garantie. Plusieurs démons doivent être introduits, comme le montre la figure ci-dessous :
Plusieurs démons résolvent le problème de disponibilité, mais des problèmes de cohérence surviennent. Comment parvenir à un accord sur la disponibilité d'un certain maître ? Par exemple, dans la figure ci-dessus, les deux réseaux du démon1 et du maître sont bloqués, mais la connexion entre le démon et le maître est fluide. Le nœud maître doit-il basculer à ce moment-là ?
Sentinel de Redis fournit un ensemble de mécanismes d'interaction entre plusieurs démons. Plusieurs démons forment un cluster et deviennent un cluster sentinelle. Comme le montre la figure ci-dessous :
Ces nœudscommuniquent, élisent et négocient entre eux, et font preuve de cohérence dans la découverte des pannes et la décision de basculement du nœud maître.
Le cluster sentinelle surveille un nombre illimité de maîtres et d'esclaves sous le maître et met automatiquement à niveau le maître hors ligne d'un esclave sous celui-ci vers un nouveau maître pour continuer à traiter les demandes de commandes../redis-sentinel ../sentinel.confou la commande :
./redis-server ../sentinel.conf --sentinelQuand un Sentinel démarre, il doit effectuer les étapes suivantes :
Initialiser le serveur
Sentinel Essence Ce qui précède est un serveur Redis fonctionnant dans un mode spécial. Il effectue des tâches différentes d'un serveur Redis ordinaire, et le processus d'initialisation n'est pas exactement le même. Par exemple, l'initialisation ordinaire du serveur Redis chargera les fichiers RDB ou AOF pour restaurer les données, mais Sentinel ne les chargera pas au démarrage car Sentinel n'utilise pas de base de données.Remplacez le code utilisé par les serveurs Redis ordinaires par des codes spécifiques à Sentinel
Remplacez certains des codes utilisés par les serveurs Redis ordinaires par des codes spécifiques à Sentinel. Par exemple, un serveur Redis normal utilise server.c/redisCommandTable comme table de commandes du serveur :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 utilise sentinel.c/sentinelcmds comme liste de serveurs, comme indiqué ci-dessous :
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
Le serveur initialisera une structure sentinel.c/sentinelState (enregistrera tous les statuts liés aux fonctions Sentinel dans le serveur).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? */ }
Initialiser la liste des serveurs maîtres de surveillance de Sentinel en fonction du fichier de configuration donné
L'initialisation de l'état de Sentinel déclenchera l'initialisation du dictionnaire maître, et l'initialisation du dictionnaire maître est basée sur le fichier de configuration Sentinel chargé pour procéder. La clé du dictionnaire est le nom du serveur principal de surveillance, et la valeur du dictionnaire est la structure sentinel.c/sentinelRedisInstance correspondant au serveur principal surveillé. Certains attributs de la structure sentinelRedisInstance sont les suivants :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. */ }Par exemple, lors du démarrage de Sentinel, le fichier de configuration suivant est configuré :
# 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 900000Ensuite, Sentinel créera la structure d'instance comme indiqué ci-dessous pour le serveur principal master1 : Statut Sentinel Et la structure du dictionnaire maître est la suivante :
Créer une connexion réseau au serveur principal
Créer une connexion réseau au serveur principal surveillé Sentinel deviendra le client. du serveur principal et envoyez-la à la commande du serveur principal et obtenez des informations à partir des réponses de la commande. Sentinel créera deux connexions réseau asynchrones au serveur principal :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如下图所示:
Lorsqu'un maître tombe en panne, plusieurs nœuds sentinelles peuvent découvrir et confirmer mutuellement « l'état d'indisponibilité subjectif » par interaction en même temps, atteindre « l'état d'indisponibilité objectif » en même temps et planifier de lancer un basculement. Mais en fin de compte, il ne peut y avoir qu'un seul nœud sentinelle comme initiateur du basculement, alors un Sentinel Leader doit être élu et un processus d'élection du Sentinel Leader doit être lancé.
Le mécanisme Sentinel de Redis utilise quelque chose de similaire au protocole Raft pour implémenter cet algorithme d'élection :
1 La variable d'époque de sentinelState est similaire au terme (tour électoral) dans le protocole raft.
2. Chaque nœud sentinelle qui confirme que le maître est "objectivement indisponible" diffusera sa propre demande d'élection aux environs (SENTINEL is-master-down-by-addr
3 Si chaque nœud sentinelle qui reçoit la demande d'élection n'a pas reçu d'autres demandes d'élection, il définira l'intention sur la première sentinelle candidate. et répondez-y (Premier arrivé, premier servi) ; si l'intention a été exprimée lors de ce tour, les autres candidats seront rejetés et l'intention existante recevra une réponse (comme mentionné ci-dessus pour les trois paramètres) Réponse Multi Bulk, down_state est 1, leader_runid est l'ID d'exécution de la sentinelle source qui a initié la demande d'élection reçue pour la première fois, leader_epoch est l'époque de configuration de la sentinelle source qui a initié la demande d'élection reçue pour la première fois)
4. le nœud sentinelle qui élit la demande reçoit plus de la moitié des intentions d'accepter une sentinelle participante (peut-être elle-même), alors la sentinelle est déterminée comme étant le leader. Si ce tour dure assez longtemps et qu'aucun leader n'est élu, le tour suivant sera lancé
leader sentinelle Après confirmation, leader sentinelle sélectionne un parmi tous les esclaves du maître selon certaines règles comme nouveau maître.
Une fois le chef sentinelle élu, le chef sentinelle effectue un basculement sur le maître hors ligne :
Le chef sentinelle en sélectionne un parmi tous les esclaves du maître hors ligne qui est en bon état, un esclave avec complétez les données, puis envoyez la commande :SLAVEOF no one à cet esclave pour convertir cet esclave en maître.
Voyons comment le nouveau master est sélectionné ? Le leader Sentinel enregistrera tous les esclaves hors ligne dans une liste, puis filtrera et filtrera selon les règles suivantes :
L'esclave la plus prioritaire, identifié par l'option replica-priority dans la configuration redis.conf, la valeur par défaut est 100, plus la priorité de réplication est faible, plus la priorité est élevée. 0 est une priorité spéciale, indiquant qu'il ne peut pas être mis à niveau vers le niveau maître.
S'il y a plusieurs esclaves avec des priorités égales, l'esclave avec le plus grand décalage de réplication sera sélectionné(les données sont plus complètes)
sélectionnez l'esclave avec le plus petit ID d'exécution
Ensuite, Sentinel enverra des informations à l'esclave mis à niveau à une fréquence d'une fois par seconde (généralement une fois toutes les dix secondes). Lorsque le rôle de réponse passe d'esclave à maître, le chef Sentinel saura qu'il a été mis à niveau vers maître.
.
Par défaut, Sentinel exécute les informations sur le maître et l'esclave toutes les dix secondes. pour découvrir les informations de changement de maître. Relation maître-esclave et découverte de nouveaux nœuds esclaves.
Par défaut, Sentinel envoie un message au canal _sentinel_:hello de tous les maîtres et esclaves surveillés via des connexions de commande toutes les deux secondes pour interagir avec d'autres sentinelles.
Par défaut, Sentinel envoie un PING au maître, à l'esclave et aux autres sentinelles toutes les secondes. Commande pour déterminer si l'autre partie est hors ligne
Le chef sentinelle est élu selon certaines règles.
Le Sentinel Leader effectue une opération de basculement et élit un nouveau maître pour remplacer le maître hors ligne.
Pour plus de connaissances sur la programmation, veuillez visiter :
Introduction à la programmationCe 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!