Redis集群的主从切换研究

栏目: 数据库 · Redis · 发布时间: 5年前

内容简介:6.6.3.6.4.

目录

6. 一次主从切换记录 1 4

6.3. 其它 master 日志 4

6.4. 其它 master 日志 5

7. 一次主从切换记录 2 6

7.3. 其它 master 日志 6

7.4. 其它 master 日志 7

8. slave 延迟发起选举代码 7

1.  前言

Redis 官方 原文: https://redis.io/topics/cluster-spec 。另外,从Redis-5.0 开始, slave 已改叫 replica ,配置项和部分文档及变量已做改名。

Redis 集群的主从切换采取选举机制,要求少数服从多数,而参与选举的只能为 master ,所以只有多数 master 存活动时才能进行,选举由 slave 发起。

Redis 用了和 Raft 算法 term (任期)类似的的概念,在 Redis 中叫作 epoch (纪元), epoch 是一个无符号的 64 整数,一个节点的 epoch 0 开始。

如果一个节点接收到的 epoch 比自己的大,则将自已的 epoch 更新接收到的 epoch (假定为信任网络,无拜占庭将军问题)。

每个 master 都会在 ping pong 消息中广播自己的 epoch 和所负责的 slots 位图, slave 发起选举时,创建一个新的 epoch (增一), epoch 的值会持久化到文件 nodes.conf 中,如(最新 epoch 值为 27 ,最近一次投票给了 27 ):

vars currentEpoch 27 lastVoteEpoch 27

2.  slave 发起选举

只有 master fail 状态, slave 才会发起选举。但并不是 master fail 时立即发起选举,而是延迟下列随机时长,以避免多个 slaves 同时发起选举(至少延迟 0.5 秒后才会发起选举):

500 milliseconds + random delay between 0  and 500 milliseconds +   SLAVE_RANK  * 1000 milliseconds

一个 slave 发起选举的条件:

1) 它的 master fail 状态(非 pfail 状态);

2) 它的 master 至少负责了一个 slot

3) slave master 的复制连接断开时间不超过给定的值(值可配置,目的是确保 slave 上的数据足够完整, 所以运维时不能任由一个 slave 长时间不可用,需要通过监控将异常的 slave 及时恢复 )。

发起选举前, slave 先给自己的 epoch (即 currentEpoch )增一,然后请求其它 master 给自己投票。 slave 是通过广播 FAILOVER_ AUTH _REQUEST 包给集中的每一个 masters

slave 发起投票后,会等待至少两倍 NODE_TIMEOUT 时长接收投票结果,不管 NODE_TIMEOUT 何值,也至少会等待 2 秒。

master 接收投票后给 slave 响应 FAILOVER_ AUTH_ACK ,并且在( NODE_TIMEOUT*2 )时间内不会给同一 master 的其它 slave 投票。

如果 slave 收到 FAILOVER_ AUTH_ACK 响应的 epoch 值小于自己的 epoch ,则会直接丢弃。一旦 slave 收到多数 master FAILOVER_ AUTH_ACK ,则声明自己赢得了选举。

如果 slave 在两倍的 NODE_TIMEOUT 时间内(至少 2 秒)未赢得选举,则放弃本次选举,然后在四倍 NODE_TIMEOUT 时间(至少 4 秒)后重新发起选举。

只所以强制延迟至少 0.5 选举,是为确保 master fail 状态在整个集群内传开,否则可能只有小部分 master 知晓,而 master 只会给处于 fail 状态的 master slaves 投票。如果一个 slave master 状态不是 fail ,则其它 master 不会给它投票, Redis 通过八卦协议(即 Gossip 协议,也叫谣言协议)传播 fail 。而在固定延迟上再加一个随机延迟,是为了避免多个 slaves 同时发起选举。

slave SLAVE_RANK 是一个与 master 复制数有关的值,具有最新复制时 SLAVE_RANK 值为 0 ,第二则为 1 ,以此类推。这样可让具有最全数据的 slave 优先发起选举。当具有更高 SLAVE_RANK 值的 slave 如果没有当选,则其它 slaves 会很快发起选举(至少 4 秒后)。

slave 赢得选举后,会向集群内的所有节点广播 pong ,以尽快完成重新配置(体现在 node.conf 的更新)。当前未能到达的节点,最终也会完成重新配置。

其它节点会发现有两个相同的 master 负责相同的 slots ,这时就看哪个 master epoch 值更大。

slave 成为 master 后,并不立即服务,而是留了一个时间差。

3.  master 响应选举

master 收到 slave 的投票请求 FAILOVER_ AUTH _REQUEST 后,只有满足下列条件时,才会响应投票:

1) 对一个 epoch ,只投票一次;

2) 会拒绝所有更小 epoch 的投票请求;

3) 不会给小于 lastVoteEpoch epoch 投票;

4) master 只给 master 状态为 fail slave 投票;

5) 如果 slave 请求的 currentEpoch 小于 master currentEpoch ,则 master 忽略该请求,但下列情况例外:

假设 master的currentEpoch值为5,lastVoteEpoch值为1(当有选举失败会出现这个情况,亦即currentEpoch值增加了,但因为选举失败,lastVoteEpoch值未变);

slave的currentEpoch值为3;

slave增一,使用值为4的epoch发起选举,这个时候master会响应epoch值为5,不巧这个响应延迟了;

slave重新发起选举,这个时候选举用的epoch值为5(每次发起选举epoch值均需增一),凑巧这个时候原来延迟的响应达到了,这个时候原来延迟的响应被slave认为有效。

master 投票后,会用请求中的 epoch 更新本地的 lastVoteEpoch ,并持久化到 node.conf 文件中。 master 不会参与选择最优的 slave ,由于最优的 slave 有最好的 SLAVE_RANK ,因此最优的 slave 可相对更快发起选举。

4.  选举示例

假设一个 master A B C 三个 slaves 节点,当这个 master 不可达时:

1) 假设 slave A 赢得选举成为 master

2) slave A 因为网络分区不再可用;

3) slave B 赢得选举;

4) slave B 因为网络分区不再可用;

5) 网络分区修复, slave A 又可用。

B 挂了, A 又可用。同一时刻, slave C 发起选举,试图替代 B 成为 master 。由于 slave C master 已不可用,所以它能够选举成为 master ,并将 configEpoch 值增一。而 A 将不能成为 master ,因为 C 已成为 master ,并且 C epoch 值更大。

5.  哈希槽传播方式

有两种哈希槽( hash slot )传播途径:

1) 心跳消息( Heartbeat messages )。节点在发送 ping pong 消息时,总是携带了它所负责(或它的 master 所负责)的 哈希槽信息;

2) 更新消息( UPDATE messages )。由于心跳包还包含了 epoch 信息,当消息接收者发现心跳包携带的信息陈旧时,会响应更新的信息,这样强迫发送者更新哈希槽。

6.  一次主从切换记录 1

测试集群运行在同一个物理机上, cluster-node-timeout 值比 repl-timeout 值大。

6.1.  相关参数

cluster-slave-validity-factor值为1

cluster-node-timeout值为 3 0 000

repl-ping-slave-period值为 1

repl-timeout 值为 10

6.2.  时间点记录

master FAIL 之时的 1 秒左右时间内,即为主从切换之时。

master A标记 fail时间:20:12: 55 .467

master B 标记 fail时间:20:12:55.467

master A投票时间:20:12:56.164

master B投票时间:20:12:56.164

slave发起选举时间:20:12: 56 .160

slave准备发起选举时间:20:12:55.558(延迟579毫秒)

slave发现和master心跳超时时间:20:12: 32 .810( 在这之后 24 秒才发生主从切换

slave收到其它master发来的自己的master为 fail 时间:20:12:55.467

切换前服务最后一次正常时间:(服务异常约发生在 )20:12:22/279275

切换后服务恢复正常时间:20:12:59/278149

服务不可用时长:约 37秒

6.3.  其它 master 日志

master ID c67dc9e02e25f2e6321df8ac2eb4d99789917783

30613:M 04 Jan 2019 20:12:55.467 * FAIL message received from bfad383775421b1090eaa7e0b2dcfb3b38455079 about 44eb43e50c101c5f44f48295c42dda878b6cb3e9   // 从其它master收到 44eb43e50c101c5f44f48295c42dda878b6cb3e9 已fail消息

30613:M 04 Jan 2019 20:12:55.467 # Cluster state changed: fail

30613:M 04 Jan 2019 20:12:56.164 # Failover auth granted to 0ae8b5400d566907a3d8b425d983ac3b7cbd8412 for epoch 30   // 对选举投票

30613:M 04 Jan 2019 20:12:56.204 # Cluster state changed: ok

30613:M 04 Jan 2019 20:12:56.708 * Ignoring FAIL message from unknown node 082c079149a9915612d21cca8e08c831a4edeade about 44eb43e50c101c5f44f48295c42dda878b6cb3e9

6.4.  其它 master 日志

master ID bfad383775421b1090eaa7e0b2dcfb3b38455079

30614:M 04 Jan 2019 20:12:55.467 * Marking node 44eb43e50c101c5f44f48295c42dda878b6cb3e9  as failing (quorum reached).  // 标记 44eb43e50c101c5f44f48295c42dda878b6cb3e9 为已fail

30614:M 04 Jan 2019 20:12:56.164 # Failover auth granted to 0ae8b5400d566907a3d8b425d983ac3b7cbd8412 for epoch 30   // 对选举投票

30614:M 04 Jan 2019 20:12:56.709 * Ignoring FAIL message from unknown node 082c079149a9915612d21cca8e08c831a4edeade about 44eb43e50c101c5f44f48295c42dda878b6cb3e9

6.5.  slave 日志

slave master ID 44eb43e50c101c5f44f48295c42dda878b6cb3e9 slave 自己的 ID 0ae8b5400d566907a3d8b425d983ac3b7cbd8412

30651:S 04 Jan 2019 20:12: 32 .810 # MASTER timeout : no data nor PING received...  // 发现master超时,master异常10秒后发现,原因是 repl-timeout 的值为10

30651:S 04 Jan 2019 20:12:32.810 # Connection with master lost.

30651:S 04 Jan 2019 20:12:32.810 * Caching the disconnected master state.

30651:S 04 Jan 2019 20:12:32.810 * Connecting to MASTER 1.9.16.9:4073

30651:S 04 Jan 2019 20:12:32.810 * MASTER<-> REPLICA sync started

30651:S 04 Jan 2019 20:12:32.810 * Non blocking connect for SYNC fired the event.

30651:S 04 Jan 2019 20:12:43.834 # Timeout connecting to the MASTER...

30651:S 04 Jan 2019 20:12:43.834 * Connecting to MASTER 1.9.16.9:4073

30651:S 04 Jan 2019 20:12:43.834 * MASTER<-> REPLICA sync started

30651:S 04 Jan 2019 20:12:43.834 * Non blocking connect for SYNC fired the event.

30651:S 04 Jan 2019 20:12:54.856 # Timeout connecting to the MASTER...

30651:S 04 Jan 2019 20:12:54.856 * Connecting to MASTER 1.9.16.9:4073

30651:S 04 Jan 2019 20:12:54.856 * MASTER<-> REPLICA sync started

30651:S 04 Jan 2019 20:12:54.856 * Non blocking connect for SYNC fired the event.

30651:S 04 Jan 2019 20:12:55.467 * FAIL message received from bfad383775421b1090eaa7e0b2dcfb3b38455079 about 44eb43e50c101c5f44f48295c42dda878b6cb3e9  // 从其它master收到自己的master的 FAIL 消息

30651:S 04 Jan 2019 20:12:55.467 # Cluster state changed: fail

30651:S 04 Jan 2019 20:12:55.558 # Start of election delayed for 579 milliseconds (rank #0, offset 227360).  // 准备发起选举,延迟579毫秒,其中500毫秒为固定延迟,279秒为随机延迟,因为RANK值为0,所以RANK延迟为0毫秒

30651:S 04 Jan 2019 20:12:56.160 # Starting a failover election for epoch 30.   // 发起选举

30651:S 04 Jan 2019 20:12:56.180 # Failover election won: I'm the new master.   // 赢得选举

30651:S 04 Jan 2019 20:12:56.180 # configEpoch set to 30 after successful failover

30651:M 04 Jan 2019 20:12:56.180 # Setting secondary replication ID to 154a9c2319403d610808477dcda3d4bede0f374c, valid up to offset: 227361. New replication ID is 927fb64a420236ee46d39389611ab2d8f6530b6a

30651:M 04 Jan 2019 20:12:56.181 * Discarding previously cached master state.

30651:M 04 Jan 2019 20:12: 56 .181 # Cluster state changed: ok

30651:M 04 Jan 2019 20:12:56.708 * Ignoring FAIL message from unknown node 082c079149a9915612d21cca8e08c831a4edeade about 44eb43e50c101c5f44f48295c42dda878b6cb3e9   // 忽略来自非集群成员 1.9.16.9:407 7的消息

7.  一次主从切换记录 2

测试集群运行在同一个物理机上, cluster-node-timeout 值比 repl-timeout 值小。

7.1.  相关参数

cluster-slave-validity-factor值为1

cluster-node-timeout值为 1 0 000

repl-ping-slave-period值为 1

repl-timeout 值为 30

7.2.  时间点记录

master FAIL 之时的 1 秒左右时间内,即为主从切换之时。

master A标记 fail时间:20:37:10.398

master B 标记 fail时间:20:37:10.398

master A投票时间:20:37:11.084

master B投票时间:20:37:11.085

slave发起选举时间:20:37:11.077

slave准备发起选举时间:20:37:10.475(延迟539毫秒)

slave发现和master心跳超时时间: 没有发生,因为 slave在超时之前已成为master

slave收到其它master发来的自己的master为 fail 时间:20:37:10.398

切换前服务最后一次正常时间:20:36:55/266889(服务异常约发生在 56秒

切换后服务恢复正常时间:20:37:12/265802

服务不可用时长:约 17秒

7.3.  其它 master 日志

master ID c67dc9e02e25f2e6321df8ac2eb4d99789917783

30613:M 04 Jan 2019 20:37:10.398 * Marking node 44eb43e50c101c5f44f48295c42dda878b6cb3e9 as failing (quorum reached).

30613:M 04 Jan 2019 20:37:10.398 # Cluster state changed: fail

30613:M 04 Jan 2019 20:37:11.084 # Failover auth granted to 0ae8b5400d566907a3d8b425d983ac3b7cbd8412 for epoch 32

30613:M 04 Jan 2019 20:37:11.124 # Cluster state changed: ok

30613:M 04 Jan 2019 20:37:17.560 * Ignoring FAIL message from unknown node 082c079149a9915612d21cca8e08c831a4edeade about 44eb43e50c101c5f44f48295c42dda878b6cb3e9

7.4.  其它 master 日志

master ID bfad383775421b1090eaa7e0b2dcfb3b38455079

30614:M 04 Jan 2019 20:37:10.398 * Marking node 44eb43e50c101c5f44f48295c42dda878b6cb3e9 as failing (quorum reached).

30614:M 04 Jan 2019 20:37:11.085 # Failover auth granted to 0ae8b5400d566907a3d8b425d983ac3b7cbd8412 for epoch 32

30614:M 04 Jan 2019 20:37:17.560 * Ignoring FAIL message from unknown node 082c079149a9915612d21cca8e08c831a4edeade about 44eb43e50c101c5f44f48295c42dda878b6cb3e9

7.5.  slave 日志

slave master ID 44eb43e50c101c5f44f48295c42dda878b6cb3e9 slave 自己的 ID 0ae8b5400d566907a3d8b425d983ac3b7cbd8412

30651:S 04 Jan 2019 20:37:10.398 * FAIL message received from c67dc9e02e25f2e6321df8ac2eb4d99789917783 about 44eb43e50c101c5f44f48295c42dda878b6cb3e9

30651:S 04 Jan 2019 20:37:10.398 # Cluster state changed: fail

30651:S 04 Jan 2019 20:37:10.475 # Start of election delayed for 539 milliseconds (rank #0, offset 228620).

30651:S 04 Jan 2019 20:37:11.077 # Starting a failover election for epoch 32.

30651:S 04 Jan 2019 20:37:11.100 # Failover election won: I'm the new master.

30651:S 04 Jan 2019 20:37:11.100 # configEpoch set to 32 after successful failover

30651:M 04 Jan 2019 20:37:11.100 # Setting secondary replication ID to 0cf19d01597610c7933b7ed67c999a631655eafc, valid up to offset: 228621. New replication ID is 53daa7fa265d982aebd3c18c07ed5f178fc3f70b

30651:M 04 Jan 2019 20:37:11.101 # Connection with master lost.

30651:M 04 Jan 2019 20:37:11.101 * Caching the disconnected master state.

30651:M 04 Jan 2019 20:37:11.101 * Discarding previously cached master state.

30651:M 04 Jan 2019 20:37:11.101 # Cluster state changed: ok

30651:M 04 Jan 2019 20:37:17.560 * Ignoring FAIL message from unknown node 082c079149a9915612d21cca8e08c831a4edeade about 44eb43e50c101c5f44f48295c42dda878b6cb3e9

8.  slave 延迟发起选举代码

// 摘自 Redis-5.0.3

// cluster.c

/* This function is called if we are a slave node and our master serving

* a non-zero amount of hash slots is in FAIL state.

*

* The gaol of this function is:

* 1) To check if we are able to perform a failover, is our data updated?

* 2) Try to get elected by masters.

* 3) Perform the failover informing all the other nodes.

*/

void clusterHandleSlave Failover (void) {

。。。。。。

/* Check if our data is recent enough according to the slave validity

* factor configured by the user.

*

* Check bypassed for manual failovers. */

if (server.cluster_slave_validity_factor &&

data_age >

(((mstime_t)server.repl_ping_slave_period * 1000) +

(server.cluster_node_timeout * server.cluster_slave_validity_factor)))

{

if (!manual_failover) {

clusterLogCantFailover(CLUSTER_CANT_FAILOVER_DATA_AGE);

return;

}

}

/* If the previous failover attempt timedout and the retry time has

* elapsed, we can setup a new one. */

if (auth_age > auth_retry_time) {

server.cluster-> failover_auth_time  = mstime() +

500  + /* Fixed delay of 500 milliseconds , let FAIL msg propagate. */

random () % 500; /* Random delay between 0 and 500 milliseconds. */

server.cluster->failover_auth_count = 0;

server.cluster->failover_auth_sent = 0;

server.cluster->failover_auth_rank = clusterGetSlaveRank();

/* We add another delay that is proportional to the slave rank.

* Specifically 1 second * rank. This way slaves that have a probably

* less updated replication offset, are penalized. */

server.cluster-> failover_auth_time  +=

server.cluster-> failover_auth_rank  * 1000;

/* However if this is a manual failover, no delay is needed. */

if (server.cluster->mf_end) {

server.cluster->failover_auth_time = mstime();

server.cluster->failover_auth_rank = 0;

}

serverLog(LL_WARNING,

"Start of election delayed for %lld milliseconds "

"(rank #%d, offset %lld).",

server.cluster->failover_auth_time - mstime(),

server.cluster->failover_auth_rank,

replicationGetSlaveOffset());

/* Now that we have a scheduled election, broadcast our offset

* to all the other slaves so that they'll updated their offsets

* if our offset is better. */

clusterBroadcastPong(CLUSTER_BROADCAST_LOCAL_SLAVES);

return;

}

。。。。。。

}


以上所述就是小编给大家介绍的《Redis集群的主从切换研究》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java 8实战

Java 8实战

厄马(Raoul-Gabriel Urma)、弗斯科(Mario Fusco)、米克罗夫特(Alan Mycroft) / 陆明刚、劳佳 / 人民邮电出版社 / 2016-4-1 / CNY 79.00

本书全面介绍了Java 8 这个里程碑版本的新特性,包括Lambdas、流和函数式编程。有了函数式的编程特性,可以让代码更简洁,同时也能自动化地利用多核硬件。全书分四个部分:基础知识、函数式数据处理、高效Java 8 编程和超越Java 8,清晰明了地向读者展现了一幅Java 与时俱进的现代化画卷。一起来看看 《Java 8实战》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器