zoukankan      html  css  js  c++  java
  • Redis的cluster模式

    Redis集群是Redis提供的分布式数据库方案,集群通过分片(Sharding)来进行数据共享,并提供复制和故障转移功能。

    节点

    一个节点就是一个运行在集群模式下的Redis服务器,Redis服务器在启动的时候会根据cluster-enabled配置项来决定是否开启服务器的集群模式。

    • 节点当前状态
    typedef struct clusterNode {
        //  创建节点时间
        mstime_t ctime;
        //  节点的名字,40个十六进制字符组成
        char name[CLUSTER_NAMELEN];
        //  节点标识
        //  使用各种不同的标识值记录节点的角色(比如:主节点、从节点)
        //  以及节点目前所处的状态(比如:在线或者下线)
        int flags;
        //  节点当前的配置纪元,用于实现故障转移
        uint64_t configEpoch;
        //  记录节点的槽指派信息
        unsigned char slots[CLUSTER_SLOTS/8];
        //  记录节点负责处理的槽的数量
        int numslots;
        //  主节点的slave节点数量
        int numslaves;
        //  从节点信息
        struct clusterNode **slaves;
        //  ……
        //  节点的ip地址
        char ip[NET_IP_STR_LEN];
        //  节点的端口号
        int port;
        //  保存连接节点所需的有关信息
        clusterLink *link; 
        //  ……
    } clusterNode;
    
    • 节点所需的有关信息,可以理解为是clusterNode的扩展信息用clusterNode.link来存储
    typedef struct clusterLink {
        //  连接的创建时间
        mstime_t ctime;
        //  输出缓冲区
        sds sndbuf;
        //  输入缓冲区
        sds rcvbuf;
        //  与这个连接相关联的节点
        struct clusterNode *node;
    } clusterLink;
    
    • 集群状态信息,记录了在当前节点的视角下,集群目前所处的状态
    typedef struct clusterState {
        //  指向当前节点的指针
        clusterNode *myself;
        //  集群当前的配置纪元,用于实现故障转移
        uint64_t currentEpoch;
        //  集群当前的状态:是在线还是下线
        int state;
        //  集群中至少处理着一个槽的节点的数量
        int size;
        //  集群节点名单(包括myself节点)
        //  字典的键为节点的名字,字典的值为节点对应的clusterNode结构
        dict *nodes;
        //  ……
    } clusterState;
    

    通过发送CLUSTER MEET命令,可以让发送命令的节点A和接收命令的节点B彼此都添加到clusterNode.nodes中,然后节点A将节点B的信息通过Gossip协议传播给集群中的其他节点,让其他节点也与节点B进行握手,最终,经过一段时间后,节点B会被集群中的所有节点认识。

    槽指派

    Redis集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被分为16384个槽,集群中的每个节点可以处理0个或者最多16384个槽。所有的槽都有节点处理时,集群就属于上线状态,否则下线状态。

    在集群中执行的命令

    当数据库中的16384个槽都进行了指派后,集群就会进入上线状态,客户端就可以向集群中的节点发送数据命令了,具体步骤如下:

    1. 计算键属于哪个槽
    2. 判断槽是否由当前节点负责处理,如果clusterNode.nodes[i]等于clusterNode.myself,那就说明i是由当前节点负责,节点可以执行客户端发送的命令
    3. MOVED错误,当节点发现键所在的槽并非由自己负责处理的时候,节点就会向客户端返回一个MOVED错误(MOVED <slot> <ip>:<port>),引导客户端转向至正在负责槽的节点

    重新分片

    Redis集群的重新分片操作可以将任意数量已经指派给某个节点(源节点)的槽改为指派给另一个节点(目标节点),并且相关槽所属的键值对也会从源节点被移动到目标节点。

    重新分片的步骤

    Redis集群的重新分片操作是由Redis的集群管理软件redis-trib负责执行的,具体步骤如下:

    1. redis-trib对目标节点发送CLUSTER SETSLOT <slot> IMPORTING <source_id>命令,让目标节点准备好从源节点导入属于槽slot的键值对
    2. redis-trib对源节点发送CLUSTER SETSLOT <slot> MIGRATING <target_id>命令,让源节点准备好将属于槽slot的键值对迁移至目标节点
    3. redis-trib向源节点发送CLUSTER GETKEYSINSLOT <slot> <count>命令,获得最多count个属于槽slot的键值对的键名
    4. 对于步骤3获得的每个键名,redis-trib都向源节点发送一个MIGRATE <target_ip> <target_port> <key_name> 0 <timeout>命令,将被选中的键原子地从源节点迁移至目标节点
    5. 重复执行步骤3和步骤4,直到源节点保存的所有属于槽slot的键值对都被迁移至目标节点为止
    6. redis-trib向集群中的任意一个节点发送CLUSTER SETSLOT <slot> NODE <target_id>命令,将槽slot指派给目标节点,这一个指派信息会通过消息发送至整个集群,最终集群中的所有节点都会直到slot已经指派给了目标节点
    ASK错误

    当被迁移槽的一部分键值对保存在源节点里面,而另一部分键值对保存在目标节点里时,如果客户端向源节点发送一个与数据库键有关的命令,且要处理的键正好在迁移的槽时:

    1. 源节点会先在自己的数据库里查找指定的键,如果找到就返回
    2. 如果源节点中没能找到,那么这个键可能已经被迁移到目标节点,源节点将向客户端返回一个ASK错误,指引客户端转向正在导入槽的目标节点
    3. 当客户端接收到ASK错误并转向正在导入槽的节点时,客户端会先向节点发送一个ASKING命令,然后才重新发送想要执行的命令,这是因为客户端如果不发送ASKING命令,而直接发送想要执行的命令的话,那么客户端发送的命令将被节点拒绝执行,返回MOVED错误
    ASK错误和MOVED错误的区别

    ASK错误和MOVED错误都会导致客户端转向,它们的区别在于:

    1. MOVED错误代表槽的负责权已经从一个节点转移到了另一个节点
    2. ASK错误只是两个节点在迁移槽的过程中使用的一种临时措施

    复制和故障转移

    Redis集群中的节点分为主节点(master)和从节点(slave),其中master用于处理槽,而slave用于复制某个master,并在被复制的master下线时,代替下线master继续处理命令请求

    设置从节点

    向一个节点发送CLUSTER REPLICATE <node_id>命令,可以让接收命令的节点成为node_id所指定节点的从节点,并开始对主节点进行复制

    故障检测

    集群中每个节点都会定期地向集群中的其他节点发送PING消息,以此来检测对方是否在线。

    • 如果接收PING消息的节点没有在规定的时间内,向发送PING消息的节点返回PONG消息,那么发送PING消息的节点就会将接收PING消息的节点标记为疑似下线
    • 如果一个集群里面,半数以上负责处理槽的主节点都将某个主节点A报告为疑似下线,那么这个主节点A将被标记为已下线,并向集群广播一个关于主节点A已下线的消息,所有收到消息的主节点都会立即将主节点A标记为已下线
    故障转移

    当一个节点发现自己正在复制的主节点已下线时,从节点将开始对下线主节点进行故障转移,步骤如下:

    1. 复制下线主节点的所有从节点里面,会有一个从节点被选中
    2. 被选中的从节点执行SLAVEOF no one命令,成为新的主节点
    3. 新的主节点会撤销所有已下线主节点的槽指派,并将这些槽指派全部指向自己
    4. 新的主节点向集群广播一条PONE消息,通知所有其他节点自己已经成功接管了已下线节点负责处理的槽
    5. 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成
  • 相关阅读:
    DataGrip破解,汉化. 再见navicate, 再见sqlyog
    centOS安装JIRA 破解版 亲测
    centOS yum 安装 JDK
    CentOS No manual entry for xxx 没有手册文档
    idea集成JRebel热部署破解
    springboot 拦截器取不到 ajax跨域请求的header参数
    centOS安装ELK
    产品经理的”影响力“
    系统设计的一些心得
    EXIF.Js:读取图片的EXIF信息
  • 原文地址:https://www.cnblogs.com/pinxiong/p/13288104.html
Copyright © 2011-2022 走看看