redis 03:Redis之主从复制,哨兵模式

以下参考了图灵学院的学习总结,图灵学院挺好的,值得报班!

一、概括

1、单机有什么问题

  • 单机故障
  • 容量瓶颈
  • qps瓶颈

在这里插入图片描述
2、怎么解决

主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,mester已写为主,slaver已读为主;

  • 读写分离;
  • 容灾备份;

3、怎么玩

  • 配从不配主;
  • 使用命令 SLAVEOF 动态指定主从关系 ,如果设置了密码,关联后使用 config set masterauth 密码;
  • 配置文件和命令混合使用时,如果混合使用,动态指定了主从,请注意一定要修改对应的配置文件;

二、主从复制

在这里插入图片描述在这里插入图片描述

2.1 原理:

  • 全量复制

1、如果你为master配置了一个slave,不管这个slave是否是第一次连接上Master,它都会发送一个PSYNC 命令给master请求复制数据。

2、master收到PSYNC命令后,会在后台进行数据持久化通过bgsave生成最新的rdb快照文件;持久化期间,master会继续接收客户端的请求,它会把这些可能修改数据集的请求缓存在内存中。

3、当持久化进行完 毕以后,master会把这份rdb文件数据集发送给slave。

4、slave会把接收到的数据进行持久化生成rdb,然后再加载到内存中。

5、然后,master再将之前缓存在内存中的命令发送给slave。

6、slave将buffer里的命令写到内存。

7、master通过socket长链接持续把写命令发送给从节点,保证主从数据一致性。

备注:

当master与slave之间的连接由于某些原因而断开时,slave能够自动重连Master,如果master收到了多个slave并发连接请求,它只会进行一次持久化,而不是一个连接一次,然后再把这一份持久化的数据发送给多个并发连接的slave。

全量复制消耗

  • 1.bgsave时间
  • 2.rdb文件网络传输
  • 3.从节点请求请求数据时间
  • 4.从节点加载rdb的时间
  • 5.可能的aof重写时间

主从复制(全量复制)流程图:
在这里插入图片描述

  • 数据部分复制
    当master和slave断开重连后,一般都会对整份数据进行复制。但从redis2.8版本开始,redis改用可以支 持部分数据复制的命令PSYNC去master同步数据,slave与master能够在网络连接断开重连后只进行部分 数据复制(断点续传)。 master会在其内存中创建一个复制数据用的缓存队列,缓存最近一段时间的数据,master和它所有的 slave都维护了复制的数据下标offset和master的进程id,因此,当网络连接断开后,slave会请求master 继续进行未完成的复制,从所记录的数据下标开始。如果master进程id变化了,或者从节点数据下标 offset太旧,已经不在master的缓存队列里了,那么将会进行一次全量数据的复制。

主从复制(部分复制,断点续传)流程图:
在这里插入图片描述

如果有很多从节点,为了缓解主从复制风暴(多个从节点同时复制主节点导致主节点压力过大),可以做如 下架构,让部分从节点与从节点(与主节点同步)同步数据

在这里插入图片描述

  • 缺点
    1.由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
    2.当主机宕机之后,将不能进行写操作,需要手动将从机升级为主机,从机需要重新制定master。

简单总结:
一个master可以有多个Slave
一个slave只能有一个master

数据流向是单向的,只能从主到从

2.2 搭建

redis主从架构搭建,配置从节点操作:

1、复制一份redis.conf文件,命名为redis6380.conf

2、将相关配置修改为如下值:

port 6380

pidfile /var/run/redis_6380.pid # 把pid进程号写入pidfile配置的文件

logfile "6380.log"

dir ./redisdata/port6380 # 指定数据存放目录,启动从节点前,要保证这个文件夹已新建,否则启动会失败

masterauth 123456 #master的连接密码

3、配置主从复制

replicaof 192.168.1.4 6379 # 从本机6379的redis实例复制数据,Redis 5.0之前使用slaveof

replica‐read‐only yes # 配置从节点只读

4、启动从节点

src/redis‐server redis6380.conf

5、连接从节点

redis‐cli ‐p 6380

6、测试在6379实例上写数据,6380实例是否能及时同步新修改数据

搭建事需要注意:
1、指定的文件夹(例如数据存放的文件夹)得提前建好,否则Redis无法启动;
2、replica‐read‐only yes 这个配置2.6之后默认就是,如果文件中找不到,而配置后启动有问题,可以不配置这一行。

2.3 实现搭建

这里我单独复制了3个Redis,以8001为master,8001和8002为slave;

1.新建redis8001,redis8002,redis8003文件夹;
在这里插入图片描述
2.将redis.conf文件复制在redis8001下;
3.分别修改个目录下的redis.conf文件;
redis8001/redis.conf

​	1.bind  指定本机ip 或 0.0.0.0  或者注释调,允许其他机器远程访问

​	2.port 8001

​	3.daemonize yes
  
​	4.pidfile /var/run/redis_8001.pid    # 把pid进程号写入pidfile配置的文件

​	5.dir /myredis/redis8001  # 指定数据存放目录
     
​	6.requirepass 123456  #这里是因为我Redis设置了密码连接
 
    7.logfile "8001.log"
    

4.把redis8001/redis.conf文件复制到redis8002,redis8003下;

redis8002/redis.conf

	1.:%s/8001/8002/g    批量替换
​	2.replicaof 192.168.0.104 8001 #如果在同一台机器上,使用内网IP或是127.0.0.1
​	3.masterauth 123456  #master的连接密码
    4.replica‐read‐only yes # 配置从节点只读

redis8003/redis.conf

    1.:%s/8001/8003/g    批量替换
  	2.replicaof 192.168.0.104 8001
  	3.masterauth 123456
  	4.replica‐read‐only yes # 配置从节点只读

5.分别启动8001.8002,8003实例

/home/redis/src/redis-server /home/myredis/redis8001/redis.conf
/home/redis/src/redis-server /home/myredis/redis8002/redis.conf
/home/redis/src/redis-server /home/myredis/redis8003/redis.conf

6.客户端连接

 /home/redis/src/redis-cli -h 192.168.0.104 -p 8001 -a 123456
 /home/redis/src/redis-cli -h 192.168.0.104 -p 8002 -a 123456
 /home/redis/src/redis-cli -h 192.168.0.104 -p 8003 -a 123456
 

安装成功后:
在这里插入图片描述

三、哨兵模式

3.1 介绍

  • 1、是什么,能干嘛?
    在Redis 2.8版本开始引入。哨兵的核心功能是主节点的自动故障转移。
    通俗来讲哨兵模式的出现是就是为了解决我们主从复制模式中需要我们人为操作的东西变为自动版,并且它比人为要更及时

  • 2.哨兵主要功能(做了哪些事)
    1)监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
    2)自动故障转移(Automatic Failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
    3)配置提供者(Configuration Provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
    4)通知(Notification):哨兵可以将故障转移的结果发送给客户端。
    其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置提供者和通知功能,则需要在与客户端的交互中才能体现。

  • 3.架构
    哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的Redis节点,不存储数据。
    数据节点:主节点和从节点都是数据节点。

3.2 原理

在这里插入图片描述

  • 1、基本原理

关于哨兵的原理,关键是了解以下几个概念:

(1)主观下线:在心跳检测的定时任务中,如果其他节点超过一定时间没有回复,哨兵节点就会将其进行主观下线。顾名思义,主观下线的意思是一个哨兵节点“主观地”判断下线;与主观下线相对应的是客观下线。

(2)客观下线:哨兵节点在对主节点进行主观下线后,会通过sentinel is-master-down-by-addr命令询问其他哨兵节点该主节点的状态;如果判断主节点下线的哨兵数量达到一定数值,则对该主节点进行客观下线。

需要特别注意的是,客观下线是主节点才有的概念;如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作。

  • 2、定时任务:

每个哨兵节点维护了3个定时任务。定时任务的功能分别如下:

(1)每10秒通过向主从节点发送info命令获取最新的主从结构;

发现slave节点
确定主从关系

(2)每2秒通过发布订阅功能获取其他哨兵节点的信息;SUBSCRIBE c2 PUBLISH c2 hello-redis
交互对节点的“看法”和自身情况

(3)每1秒通过向其他节点发送ping命令进行心跳检测,判断是否下线(monitor)。
心跳检测,失败判断依据

  • 3、选举

(1)选举领导者哨兵节点:当主节点被判断客观下线以后,各个哨兵节点会进行协商,选举出一个领导者哨兵节点,并由该领导者节点对其进行故障转移操作。

监视该主节点的所有哨兵都有可能被选为领导者,选举使用的算法是Raft算法;Raft算法的基本思路是先到先得:即在一轮选举中,哨兵A向B发送成为领导者的申请,如果B没有同意过其他哨兵,则会同意A成为领导者。选举的具体过程这里不做详细描述,一般来说,哨兵选择的过程很快,谁先完成客观下线,一般就能成为领导者。

(2)故障转移:选举出的领导者哨兵,开始进行故障转移操作,该操作大体可以分为3个步骤:

在从节点中选择新的主节点:选择的原则是,

1.首先过滤掉不健康的从节点;

2.然后选择优先级最高的从节点(由replica-priority指定);如果优先级无法区分,

3.则选择复制偏移量最大的从节点;如果仍无法区分,

4.则选择runid最小的从节点。

更新主从状态:通过slaveof no one命令,让选出来的从节点成为主节点;并通过slaveof命令让其他节点成为其从节点。

将已经下线的主节点(即8001)保持关注,当8001从新上线后设置为新的主节点的从节点

  • 4.实践建议

哨兵节点的数量应不止一个。一方面增加哨兵节点的冗余,避免哨兵本身成为高可用的瓶颈;另一方面减少对下线的误判。此外,这些不同的哨兵节点应部署在不同的物理机上。

哨兵节点的数量应该是奇数,便于哨兵通过投票做出“决策”:领导者选举的决策、客观下线的决策等。

各个哨兵节点的配置应一致,包括硬件、参数等;此外应保证时间准确、一致。

  • 5.总结

在主从复制的基础上,哨兵引入了主节点的自动故障转移,进一步提高了Redis的高可用性;但是哨兵的缺陷同样很明显:哨兵无法对从节点进行自动故障转移,在读写分离场景下,从节点故障会导致读服务不可用,需要我们对从节点做额外的监控、切换操作。此外,哨兵仍然没有解决写操作无法负载均衡、及存储能力受到单机限制的问题

3.3 实战

  • 1.部署主从节点
    哨兵系统中的主从节点,与普通的主从节点配置是一样的,并不需要做任何额外配置。下面分别是主节点(port=8001)和2个从节点(port=8002/8003)的配置文件;
    我们刚才搭建的主从复制就是主从节点

  • 2.部署哨兵节点
    哨兵服务不提供读写服务,仅仅用来监控主节点,当主节点不可用时,选举出新的主节点返回给客户端(redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)

注意事项:

  • 如果有密码,设置连接master和slave时的密码,注意的是sentinel不能分别为master和slave设置不同的密码,因此master和slave的密码应该设置相同。
  • 复制sentinel.conf文件时,myid是相同的,启动后哨兵节点没办法相互感知,所以到配置文件中将myId注释掉,启动时myid会自动生成的,重新启动哨兵,再次检验。
1、复制一份sentinel.conf文件

cp sentinel.conf sentinel‐26379.conf

2、将相关配置修改为如下值:

port 26379

daemonize yes

pidfile "/var/run/redis‐sentinel‐26379.pid"

logfile "sentinel-26379.log"

dir ./sentineldata        #这个目录在启动sentinel之前须新建好,否则无法启动

# sentinel monitor master‐redis‐name master‐redis‐ip master‐redis‐port quorum。quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效

sentinel monitor mymaster 192.168.0.60 6379 2  # mymaster这个名字随便取,客户端访问时会用到

sentinel auth-pass mymaster 123456  #如果redis设置了密码,需要添加 

3、启动sentinel哨兵实例

src/redis‐sentinel sentinel‐26379.conf

4、查看sentinel的info信息

src/redis‐cli ‐p 26379

127.0.0.1:26379>info

可以看到Sentinel的info里已经识别出了redis的主从

5、可以自己再配置两个sentinel,端口26380和26381,注意上述配置文件里的对应数字都要修改

3个哨兵节点的配置几乎是完全一样的,主要区别在于端口号的不同(26379 / 26380 / 26381),注意myid得保证不一样

sentinel集群都启动完毕后,会将哨兵集群的元数据信息写入所有sentinel的配置文件里去(追加在文件的 最下面),我们查看下如下配置文件sentinel-26379.conf,如下所示:
在这里插入图片描述
当redis主节点如果挂了,哨兵集群会重新选举出新的redis主节点,同时会修改所有sentinel节点配置文件 的集群元数据信息,比如8001的redis如果挂了,假设选举出的新主节点是8003,则sentinel文件里的集 群元数据信息会变成如下所示:
在这里插入图片描述

当8001的redis实例再次启动时,哨兵集群根据集群元数据信息就可以将8001端口的redis节点作为从节点 加入集群

3.4 JAVA连接

如果java客户端连接失败看看自己服务器端口有没有对外开发,也可以直接关闭防火墙;

1、客户端(jedis)访问哨兵系统(自动故障转移功能)

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
public class TestJedisSentinel {
    public static void main(String[] args)  {
        Logger logger= LoggerFactory.getLogger(TestJedisSentinel.class);
        Set<String> set=new HashSet<>();
        set.add("192.168.1.188:26379");
        set.add("192.168.1.188:26380");
        set.add("192.168.1.188:26381");
        JedisSentinelPool jedisSentinelPool=new JedisSentinelPool("mymaster",set,"123456");
        while (true) {
            Jedis jedis=null;
            try {
                jedis = jedisSentinelPool.getResource();
                String s = UUID.randomUUID().toString();
                jedis.set("k" + s, "v" + s);
                System.out.println(jedis.get("k" + s));
                Thread.sleep(3000);
            }catch (Exception e){
                logger.error(e.getMessage());
            }finally {
                if(jedis!=null){
                    jedis.close();
                }
            }
        }
    }
}

2、哨兵的spring-boot整合Redis链接代码

依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
</dependency>

Springboot配置:

spring:
  redis:
    database: 0
    timeout: 3000
    password: 123456
    sentinel: #哨兵模式
      master: mymaster #主服务器所在集群名称
      nodes: 192.168.1.188:26379,192.168.1.188:26380,192.168.1.188:26381
    lettuce: #连接池设置
      pool:
        max-idle: 50
        min-idle: 10
        max‐active: 100
        max-wait: 1000

在demo(代码略)中,写一个while(true)接口,持续往redis中set数据,并get出来。

package com.redis;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class IndexController {
 
    private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
 
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
 
    /**
     * 测试节点挂了哨兵重新选举新的master节点,客户端是否能动态感知到
     *
     * @throws InterruptedException
     */
    @RequestMapping("/test_sentinel")
    public void testSentinel() throws InterruptedException {
        int i = 1;
        while (i<=300){
            try {
                stringRedisTemplate.opsForValue().set("sentinel666"+i, "sentinelTest"+i); //jedis.set(key,value);
                System.out.println("设置key:"+ "sentinel666"+i);
                i++;
                Thread.sleep(1000);
            }catch (Exception e){
                logger.error("错误:", e);
            }
        }
    }
 
}

程序运行起来后,关闭redis server主节点8001,此时程序报错time out 3seconds()
在这里插入图片描述

报错一段时间后,哨兵选举新的主节点8003,并发给client端重新链接。且可以看到,key并没有丢失
在这里插入图片描述

重新启动8001 redis server,8001成为从节点,查看哨兵conf文件,可以看到主节点已被替换成8003
在这里插入图片描述

以上参考了图灵学院的学习总结,图灵学院挺好的,值得报班!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值