zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    java Android get date before 7 days (one week) Stack Overflow
    计算机网络与分布式系统实验室 北京大学
    得到IFrame中的Document
    eclipse如何把多个项目放在一个文件夹下
    windows 32位程序编译成64位
    iPhone5和iOS6上HTML5开发的新增功能
    Thinking in Java之接口回调改版
    Java学习笔记35:Java常用字符串操作函数
    进一步优化Bitmap Cache策略
    微软安全新闻聚焦双周刊第三十期
  • 原文地址:https://www.cnblogs.com/ilifeilong/p/12694985.html
Copyright © 2011-2022 走看看