在一个如以下列表三主三从的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
二. 槽指派
集群通过槽(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
[[email protected]01 ~]$ redis-cli -h redis-master-01 cluster addslots {0..5000}
将5001~10000的slot分配到redis-master-02
[[email protected]01 ~]$ redis-cli -h redis-master-02 cluster addslots {5001..10000}
将10001~16383的slot分配到redis-master-03
[[email protected]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.
那么如何判断某一个key应该存入到哪个slot中呢,可通过如下命令判断。
redis-master-01:6379> cluster keyslot name (integer) 5798 redis-master-01:6379> cluster keyslot age (integer) 741 redis-master-01:6379> cluster keyslot salary (integer) 975 redis-master-01:6379> cluster keyslot birthday (integer) 3211
redis将一个存入的key进行hash运算,CRC16&0x3fff,得到一个小于等于16384的整数,该整数即为要存入数据的槽号。
原文地址:https://www.cnblogs.com/ilifeilong/p/12694985.html