首页 > 数据库 >Redis系列之高可用集群模式介绍

Redis系列之高可用集群模式介绍

时间:2024-03-22 15:29:47浏览次数:37  
标签:同步 slave Redis 集群 Sentinel master 之高 节点

Redis系列之高可用集群模式介绍

1. Redis主从模式

1.1 什么是主从模式?

主从模式,是redis集群最基本的模式,主库负责读写,从库负责读。主库的数据会同步到从库,但是从库写的数据不会自动同步到主库,除非用写脚本等方式手动同步。这种模式应急能力比较差,假如出现宕机的情况,需要手动进行修改

1.2 全量同步

  1. master服务端收到slave的同步命令psync后,判断slave传过来的master_replid是否和mastermaster_replid一致,如果不一致或者传的是一个空的,就需要进行全量同步

  2. master开始执行bgsave命令,生成一个RDB文件,生成成功后,给到slave,并且将master_replidofferset传过去

  3. slave收到RDB文件后,清空slave自己内存中的数据,然后通过RDB文件重新加载数据

补充细节:

  • Redis4.0之前的版本,slavemaster传的不是master_replid,而是runid,但是runid每次实例重启都会改变,也就是会进行一次全量同步,所以Redis4.0版本后采用replid
  • master进行bgsave生成RDB文件时,因为bgsave命令是异步的,所以在同步时候,可能会接收其它指令,所以这些指令会先暂存在一个内存空间replication_buffer,等到slave加载完RDB文件后,再同步给slave
  • 设置replication_buffer大小可以通过如下进行配置
     # 256mb:硬性限制,大于256M断开连接;64mb 60:软限制,超过64M并且超过了60s还没进行同步就会断开连接
    client-output-buffer-limit replica 256mb 64mb 60
    
  • 内存空间replication_buffer不能设置太小,如果设置太小,超过了大小之后,为了数据安全,会关闭master跟从库的连接,再次连接就得重新全量同步,但是问题还在,可能导致无限同步问题

1.3 增量同步

有全量同步就会有增量同步的,那么redis什么时候会进行增量同步?增量同步的流程是怎么样的?

在全量同步时候说过,master会给slave一个偏移量offerset,如果出现slavemaster网络断开一小会等情况,导致偏移量跟master差了一点,网络恢复,slave重新跟master连接后,这时slave会发送指令,判断是否需要增量同步还是全量同步?

  1. master会判断slave传过来的master_replid是否一致,如果一致,满足条件,进行下一步校验
  2. 增量同步会根据偏移量offerset和积压缓存数据来判断,增量同步会去积压缓存replication_backlog_buffer获取数据,如果偏移量只差了3条数据,同时在积压缓存里查找得到,就会进行增量同步

补充细节:

  • master_replid一致的情况,可能也不会进行增量同步,因为积压缓存的数据,可能是被覆盖了,导致需要增量同步的数据,查找不到,为什么会被覆盖?因为积压缓存是可以设置大小的,如果内存满了,就会覆盖之前的数据
  • 设置积压缓存replication_backlog_buffer的大小
    repl-backlog-size 1mb
    

2. Redis哨兵模式

2.1 什么是哨兵模式?

Redis的主从模式是可以解决负载、数据备份等问题,但是,如果master宕机的情况,slave是不会自动升级为master的,必须手动升级,所以就有了哨兵集群的方案,以及后面介绍的cluster集群

先看看官网Sentinel的介绍

在这里插入图片描述

大概意思是Redis Sentinel在不适用Cluster集群的时候,为Redis提供了高可用性,并且提供了检测、通知、自动故障转移、配置提供等功能

监控 :能够监控我的redis实例是否正常运行

通知:如果redis的实例出现问题,能够通知给其它实例以及其它Sentinel

自动故障转移master宕机,slave可以自动升级为master

配置提供Sentinel可以提供Redis的master实例地址,那么客户端只需要跟Sentinel进行连接,master宕机了会提供新的master

总而言之,Sentinel是独立于Redis服务的单独服务,并且它们之间是相互通信的,可以画图表示一下Redis的哨兵模式:

在这里插入图片描述

2.2 故障转移流程

下面说一下,master宕机的情况,哨兵是怎么去监控的,并且怎么选举slave作为新的master的,首先,各Sentinel之间,以及Sentinelmaster/slave之间都会进行通信的,Redis故障转移的过程大致为:

在这里插入图片描述

  • 发现master故障

    1. Sentinel是会一直和master通信的,默认是1s发送ping,当某个Sentinel发现在一定时间内(down-after-milliseconds)没有收到master的有效回复,这个Sentinel就会认为这个master宕机了,这个时候还不会触发故障转移,只会标记一个SDOWN(Subjectively Down condition)状态,也就是我们讲的主观下线
    2. 之后这个sentinel会去询问其它的sentinel能否连上master,如果超过法定人数quorum都认为master不可用,都标记SDOWN状态,那么就会将master标记为ODOWN(Objectively Down condition)客观下线
  • 选举一个Sentinel来故障转移

    1. 因为Sentinel一般是集群的,所以需要选举一个Sentinel来进行故障转移就好,并且这个Sentinel在做故障转移的时候,其它Sentinel不能进行故障转移
    2. 选举这个Sentinel,有两个判断因素
      • 如果Quorum如果小于等于sentinel数量的一半,那么必须超过半数的sentinel授权,这个sentinel才可以去做故障转移,不如有5台sentinel,配置的quornum为2,那么选举时候必须有3台以上的sentinel授权
      • 如果Quorum大于Sentinel数量的一半,那么必须QuorumSentinel授权,故障迁移才能启动
  • 选举slave转变为master

    选出一个Sentinel来做故障转移后,具体选举哪个Slave来当master,需要由各种因素综合考虑:

    1. 与master的断开连接时间

      如果slave与主服务器断开时间超过主服务器配置的超时时间(down-after-milliseconds)的十倍,被认为不适合成为master,直接去除资格

    2. 配置的优先级

      配置replica-priorityreplica-priority越小,优先级越高,但是配置为0的时候,永远没有资格升级为master,具体参考https://redis.io/docs/manual/sentinel/#replica-selection-and-priorit

    3. 已复制的偏移量

      数据最新的优先升级为master

    4. Run ID

      每个实例启动都会有一个RunId,可以通过info server查看

2.3 分区下的一致性

Redis集群(分区)后,可能会有一致性的问题,也可以说是脑裂问题,其实就是有2个master,client会从不同的master写数据,从而在master恢复的时候,会导致数据丢失。

举个例子,一个集群的架构是有一个master,下面还有两个slave,假如出现masterslave连接不上,这时候就会选举,重新选举一个slave作为master,等到网络恢复后,原先的master恢复连接,在这种集群架构里肯定不能有两个master,所以会恢复原先的master地位,新选举的master变为slave,显而易见这种情况会造成数据丢失了,因为故障过程,数据还可以继续写到原先的master,一恢复网络,这个时间段写的数据都会丢失了,所以有什么方法可以避免这种情况?

首先对于这种问题,不能解决,只能避免,避免数据丢失的情况,在Redis官网给出了一种方案,需要在Redis.cfg文件中加上配置:

# 至少有1个从节点同步到我主节点的数据,这样配置就可以避免原先断网的master进行数据写入,减少数据一致性问题
min-replicas-to-write 1
# 判断上面1个的延时时间必须小于等于10s
min-replicas-max-lag 10

3. Reids Cluster模式

3.1 什么是Redis Cluster模式?

redis的哨兵模式提供了比如监控、自动故障转移等高可用方案,但是这种方案,容量相对固定,要进行持续扩容或者数据分片就不适合,所以有另外一种更复杂的集群方案,Cluster集群模式。

Cluster集群模式,Cluster模式支持多主多从,这种模式,按照key进行虚拟槽位分配,使得key分配到不同的主节点,使用这种模式使得集群节点有更大的容量,也可以持续进行扩容,如果主库节点出现宕机,也会从从库节点选出一个新的主库节点

所以,如果redis的数据量不是很大,就可以使用哨兵模式,如果Redis存储的数据量比较大,而且需要持续扩容,那么就需要选择Cluster模式

3.2 Redis Cluster特点

  • 多个节点之间按照key进行虚拟槽分配,也就是我们说的数据分片
  • 当某些节点遇到故障的时候,其他节点还能继续服务

3.3 hash slot虚拟槽

那么如何进行数据分片?数据分片相当于数据库的分表,不同的数据放到不同的表里。数据分片就是要把不同的数据放到不同的实例里面。

所以,在Redis里面提出一个Hash槽,也可以称之为虚拟槽的概念。什么是虚拟槽?其实就是虚拟节点,Redis Cluster中有16384个虚拟槽。

key和虚拟槽怎么对应?会根据CRC16取模16383得到一个0到16383的值,计算公式是:slot = CRC16(key) & 16383,通过这个公式计算得到的值就表示key在哪个虚拟槽,举例:

set k1 1: 
CRC16(k1) & 16383 = 10

set k2 1:
CRC16(k1) & 16383 = 5468

set k3 1:
CRC16(k1) & 16383 = 10988

# 所以k1、k2、k3对应的槽位分别是10、5468、10988

如果有3台主库,对应的槽位分别为

master1 0-5460虚拟槽
master2 5461-10922虚拟槽
master3 10923-16383虚拟槽

则,k1、k2、k3分别会放在master1、master2、master3

为什么使用16384个虚拟槽?

Redis的官方issues也有给出答复,作者的亲自答复,请看原文:

在这里插入图片描述

翻译下:

  • 正常的心跳包携带节点的完整配置,可以用旧的方式以幂等的方式替换,以更新旧的配置,这意味着它们包含原始形式的节点插槽配置,该节点使用2k空间和16k插槽,但如果使用65k插槽会使用令人望而止步的8k空间
  • 同时,由于其他设计权衡,Redis Cluster不太可能扩展到1000多个主节点

看了大概意思是使用这个值是基于应用场景考虑,一般Cluster不太可能扩展到1000多个主节点,所以使用2k空间和16k的插槽比较合理,也不会占用太大空间,有读者还可能不太理解,所以继续分析,在redis中,cluster节点是会相互监测进行数据交互的,所以看下交互的数据头文件,cluster.h

typedef struct {
    char sig[4];        /* Signature "RCmb" (Redis Cluster message bus). */
    uint32_t totlen;    /* Total length of this message */
    uint16_t ver;       /* Protocol version, currently set to 1. */
    uint16_t port;      /* TCP base port number. */
    uint16_t type;      /* Message type */
    uint16_t count;     /* Only used for some kind of messages. */
    uint64_t currentEpoch;  /* The epoch accordingly to the sending node. */
    uint64_t configEpoch;   /* The config epoch if it's a master, or the last
                               epoch advertised by its master if it is a
                               slave. */
    uint64_t offset;    /* Master replication offset if node is a master or
                           processed replication offset if node is a slave. */
    char sender[CLUSTER_NAMELEN]; /* Name of the sender node */
    unsigned char myslots[CLUSTER_SLOTS/8];
    char slaveof[CLUSTER_NAMELEN];
    char myip[NET_IP_STR_LEN];    /* Sender IP, if not all zeroed. */
    char notused1[34];  /* 34 bytes reserved for future usage. */
    uint16_t cport;      /* Sender TCP cluster bus port */
    uint16_t flags;      /* Sender node flags */
    unsigned char state; /* Cluster state from the POV of the sender */
    unsigned char mflags[3]; /* Message flags: CLUSTERMSG_FLAG[012]_... */
    union clusterMsgData data;
} clusterMsg;

源码里有个char类型的变量unsigned char myslots[CLUSTER_SLOTS/8];,表示的意思是为当前槽的数量除以8,因为一个char类型在c语言中大小被定义为1Byte,所以大小为16384/8/1024=2kb,所以使用16384个虚拟槽的话,只需占用2kb的空间

但是为什么作者要举例65k?因为crc16算法得到的hash值是16bit,最大的值为65536,计算占用空间达到了8kb,所以数据传输会比较慢,所以一般场景16384个虚拟槽就符合需求,就取了一个16384的值,提升传输性能

补充知识点:

  1. bit(位,又名“比特”):bit的缩写是b,是计算机中的最小数据单位(属于二进制的范畴,其实就是0或者1)

  2. Byte(字节):Byte的缩写是B,是计算机文件大小的基本计算单位。比如一个字符就是1Byte,如果是汉字,则是2Byte。

    1B(字节)=8b(位)
    1 KB = 1024 B
    1 MB = 1024 KB
    1 GB = 1024 MB
    1TB = 1024GB

标签:同步,slave,Redis,集群,Sentinel,master,之高,节点
From: https://blog.csdn.net/u014427391/article/details/136744377

相关文章

  • ELK - Win10上使用Docker搭建ES集群
    Win10上使用Docker搭建ES集群ElasticSearch离线镜像包http://www.elastic-view.cn/index.htmlES可视化管理工具http://www.elastic-view.cn/index.html单机单节点启动命令:dockerrun-d--nameelasticsearch-p9200:9200-p9300:9300-enode.name=elasticsearch......
  • 三、云原生系列—快速创建k8s生产集群
    重要写在开头,我的教程更多是记录过程,如果你不看各类开源软件的官方文档,不对linux有所了解,我的文档对你的帮助是很有限的。重要写在开头,我的教程更多是记录过程,如果你不看各类开源软件的官方文档,不对linux有所了解,我的文档对你的帮助是很有限的。重要写在开头,我的教程更多是记......
  • Redeemer(Redis)
    Redeemer(Redis)1.TASK1问题:机器上打开了哪个TCP端口?使用nmap命令扫描端口(如果以下命令效果不佳,可以添加-Pn):nmap-sS-T4-p0-6553510.129.138.161可知开放的端口号为6379/tcp。答案:63792.TASK2问题:哪个服务正在计算机上打开的端口上运行?使用命令nmap-A-p6379......
  • Redis不同的持久化方式有什么差异?我们来做个小试验。
    前言大家应该都知道,Redis持久化方式主要有两种:RDB(RedisDataBase)和AOF(Append-onlyfile)。但是他们各自存储了什么内容?有什么差异呢?今天我来给大家做个小试验。前期准备,需要安装好docker、docker-compose的运行环境。一、安装Redis1、创建相关目录,执行如下命令。mkdir-p......
  • 如何在Kubernetes集群中集成Cromwell和Volcano(概述)
    将Cromwell和Volcano在Kubernetes集群中集成,使用Volcano作为Cromwell调度器,涉及到在Kubernetes集群上安装和配置这两个系统以及确保它们能够无缝协作。以下是一个基于理解和实际操作经验的概括步骤,旨在指导如何进行这一集成:步骤1:安装Kubernetes集群确保你已经......
  • SpringBoot整合Redis:Redis优化解决数据一致性问题
    ......
  • Redis第二课,1.set key value(设置对应的key和value)2.get key(得到value值)Redis全局
    Redis的启动 redis-cli目录1.setkeyvalue(设置对应的key和value)2.getkey(得到value值)Redis全局命令(支持很多的数据结构)3.keys(用来查询当前服务器匹配的key)生产环境/线上环境4.exist(判定key是否存在):判定key是否存在​编辑5.DEL  key 返回删掉的key......
  • 记一次Redis报错问题
    问题描述在Spring项目中使用了@Cacheable注解并且将缓存放入redis,当从Redis读取缓存时提示了反序列化异常,无法构造UnmodifiableMap,没有默认的构造函数CouldnotreadJSON:Cannotconstructinstanceof`org.apache.commons.collections4.map.UnmodifiableMap`(noCreators,......
  • redis——集合,有序,慢查询, pipline与事务, bitmap ,HyperLogLog geo
    集合类型(set)saddkeyelement#向集合key添加element(如果element存在,添加失败)o(1)sremkeyelement#从集合中的element移除掉o(1)scardkey#计算集合大小sismemberkeyelement#判断element是否在集合中srandmemberkeycount#从集合中随机取出count个元素,不会破坏集......
  • golang使用redis锁(避免误解锁/死锁/过期引起并发):go-redis, redigo
    【go-redis】简单实现方式,不会死锁/误解锁packagemainimport("context""fmt""sync""time"redis2"github.com/redis/go-redis/v9")varmutexsync.Mutex//redis加锁sec:锁定秒数(避免死锁),value锁唯一值(避免误解......