Redis Cluster原理简单学习

Posted 一泽涟漪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis Cluster原理简单学习相关的知识,希望对你有一定的参考价值。

 在一个如以下列表三主三从的Redis Cluster中,集群中每个节点会在内存中保存一张关于集群信息的ClusterState和ClusterNode结构,如下所示。

主机名 IP地址 角色
redis-master-01 172.16.101.54 Master
redis-master-02 172.16.101.55 Master
redis-master-03 172.16.101.56 Master
redis-slave-01 172.16.101.58 Slave(Master:172.16.101.54)
redis-slave-02 172.16.101.59 Slave(Master:172.16.101.55)
redis-slave-03 172.16.101.60 Slave(Master:172.16.101.56)

一. 集群节点

1. 节点启动初始化

一个启用集群功能的节点在默认状态下,没有加入任何集群,而且认为节点自己就是集群中的master,在启动节点时会看到如下log

25630:M 12 Apr 00:59:59.477 * No cluster configuration found, I\'m 89a83af689b194b18c7f5c0dae105c329a6a831f
18608:M 13 Apr 23:41:18.607 * No cluster configuration found, I\'m 2840512295a3e863a4b817510323565fa5bc78e3

同时,通过集群cluster nodes命令可以看到各个节点的状态均为master节点

redis-master-01:6379> cluster nodes
dc4ee5e34a946ae7a20b58c023ce93b2775ac30d :6379 myself,master - 0 0 0 connected
redis-master-02:6379> cluster nodes
2840512295a3e863a4b817510323565fa5bc78e3 :6379 myself,master - 0 0 0 connected

各个集群节点在内存中初始化一个ClusterState内存结构,并将自己的节点信息添加到字典nodes属性中。

2. 节点与其他节点消息交互

一个集群节点启动成功后,可以通过“cluster meet ip port”命令与其他节点进行信息交互,邀请其他节点加入到自己所在的集群中,

redis-master-01:6379> cluster meet 172.16.101.55 6379
OK

其meet过程如下:

1) 节点redis-master-01通过发送"meet"消息与节点redis-master-02进行握手(handshake),同时将节点redis-master-02信息添加到内存结构ClusterState中的字典nodes属性中。

#define CLUSTERMSG_TYPE_MEET 2          /* Meet "let\'s join" message */

2) 节点redis-master-02收到节点redis-master-01的"meet"消息后,节点redis-master-02也会将节点redis-master-01添加到内存结构ClusterState中的字典nodes属性中,并向节点redis-master-01返回一条“pong”消息。

#define CLUSTERMSG_TYPE_PONG 1          /* Pong (reply to Ping) */

3) 节点redis-master-01收到节点redis-master-02的“pong”消息后,认为节点redis-master-02已经收到自己的"meet"消息,再次向节点redis-master-02发送一条“ping”消息.

#define CLUSTERMSG_TYPE_PING 0          /* Ping */

节点redis-master-02收到“ping”消息后,认为节点redis-master-01已经收到自己的"pong"回复,节点握手(handshake)完成。

4) 集群中其他节点通过gossip消息得知新节点加入集群后,使用同样的方式与新节点握手(handshake),并将新节点添加到内存结构ClusterState中的字典nodes属性中,最终,新节点会被集群中所有其他节点熟知。

redis-master-01:6379> cluster nodes
dc4ee5e34a946ae7a20b58c023ce93b2775ac30d 172.16.101.54:6379 myself,master - 0 0 0 connected
dbe28b335ba69c551029902eb83bdef92431300f 172.16.101.56:6379 master - 0 1586795007334 2 connected
2840512295a3e863a4b817510323565fa5bc78e3 172.16.101.55:6379 master - 0 1586795006331 1 connected

二. 槽指派

1.槽指派过程

集群通过槽(slot)的方式保存键值对,一个数据库被分成16384个slot,注意范围是0~16383,集群中的每个节点负责处理其中部分slot,每个键值对都存入对应的slot中,这也说明了如果某个节点宕机,该节点上对应的slot也会下线,集群将处于下线状态,slot个数定义如下。

#define CLUSTER_SLOTS 16384

即使已经有节点加入到集群中,但是集群仍然不可用,因为并没有定义集群中各个节点应该存放多少个slot。

redis-master-01:6379> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:5350
cluster_stats_messages_received:5350

 通过如下方式将16384分slot分别指派到各个节点中

将0~5000的slot分配到redis-master-01

[redis@redis-master-01 ~]$ redis-cli -h redis-master-01 cluster addslots {0..5000}

将5001~10000的slot分配到redis-master-02

[redis@redis-master-01 ~]$ redis-cli -h redis-master-02 cluster addslots {5001..10000}

将10001~16383的slot分配到redis-master-03

[redis@redis-master-01 ~]$ redis-cli -h redis-master-03 cluster addslots {10001..16383}

这里需要注意:不能在redis-cli交互式命令中执行,否则会报错

redis-master-01:6379> cluster addslots {0..5000}
(error) ERR Invalid or out of range slot

slot分配完成之后,再次查看cluster状态,集群功能已经上线

redis-master-01:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:6950
cluster_stats_messages_received:6950

每个节点的slot信息保存在每个节点内存结构ClusterState中nodes字典对应的ClusterNode的slot属性中,该slot为长度16384的二进制数组,如果该节点拥有某个slot,就将该slot对应的索引值置为1,如果没有,就将该slot置为0,如在节点redis-master-01中保存了0~5000的slot,那么0~5000的slot对应的二进制索引值均为1,而5001~16383对应的二进制索引位均为0.

2. 关于槽指派的内部实现

一个集群节点启动完成之后,节点的内存数据结构ClusterState的slots属性记录的0~16383个slot的指针均指向null,说明16384个slot暂时未指派给任何节点,例如在节点reds-master-01上“cluster addslots 0..5000”时,ClusterState的slots属性中的0~5000个slot的指针发生变化,这些指针分别指向reds-master-01节点的ClusterNode数据结构,并且该节点的ClusterNode数据结构的slots二进制位中的0~5000的索引值被置为1,同时,该节点会向集群中其他节点告知自己目前已经处理了0~5000个槽。

3. 关于键操作

在对集群键进行操作的时候,集群节点首先判断该键是否由自己所在的节点进行维护,例如,reds-master-01节点负责处理的槽位是0~5000,reds-master-02节点负责处理的槽位是5001~10000。

reds-master-01节点接收到一个写入建的请求后,首先对该key进行CRC16运算,得到一个小于等于16384的整数,该整数即为要存入数据的槽号。然后根据该整数判断该建是否由自己维护,如果是的话,就直接执行写入操作。

redis-master-01:6379> cluster keyslot age
(integer) 741
redis-master-01:6379> set age 20
OK

如果CRC校验后的整数大于5000小于10000,则会将key自动转向到负责处理该slot的节点上

$ redis-cli -c -h redis-master-01
redis-master-01:6379> cluster keyslot name
(integer) 5798
redis-master-01:6379> set name "Ting,Chris"
-> Redirected to slot [5798] located at 172.16.101.55:6379
OK
redis-master-01:6379> get name
-> Redirected to slot [5798] located at 172.16.101.55:6379
"Ting,Chris"

注意,我们进入redis-cli交互式时添加了cluster参数,说明我们进入的是集群模式的cli,如果进入单机模式的cli执行上述命令会报错,指导你到对应的节点上执行键操作。

redis-master-01:6379> set name "Ting,Chris"
(error) MOVED 5798 172.16.101.55:6379
redis-master-01:6379> get name
(error) MOVED 5798 172.16.101.55:6379

以上是关于Redis Cluster原理简单学习的主要内容,如果未能解决你的问题,请参考以下文章

第十三章 redis-cluster原理

REDIS CLUSTER 搭建,扩容缩容基本原理

Redis cluster 原理

redis cluster 集群 HA 原理和实操(史上最全面试必备)

Redis Cluster集群搭建Cluster集群扩缩容底层原理

redis cluster集群选主