• Redis 主从搭建和哨兵搭建


    主从

     

    主从搭建是后面哨兵和集群的基础,虽然生产环境很少使用。

    我们就以一主两从来搭建。我这里就用一台机器来搭建了。

    1:复制一份redis.conf配置文件命名为redis-6380.conf

    2:修改配置文件中的如下配置:

    1. port 6380 #server占用的端口号,保持唯一,避免冲突
    2. pidfile /var/run/redis_6380.pid #把pid进程号写入pidfile配置的文件
    3. logfile "6380.log" #日志文件
    4. dir ./data/6380 #指定数据的目录
    5. #bind 127.0.0.1 注释掉
    6. replicaof 127.0.0.1 6379 #从本机6379的redis实例复制数据,Redis 5.0之前使用slaveof
    7. replica-read-only yes #配置从节点只读

    同上,复制一份6381的配置文件,注意,dir目录要提前创建出来,不然会报错,如果启动成功,可以通过ps -ef | grep redis查看到三个实例了。

    用-p 端口号可以连上这三个server.

    src/redis-cli -p  port #6379-6381

    其中6379是主服务,用来写命令操作,写入之后在从服务6380,6381客户端都可以查询到。

    Redis 主从工作原理

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

    2:master收到PSYNC命令后,会通过bgsave生成当时的rdb快照,master会继续接收客户端发送的命令请求,它会把这个期间可能修改数据集的请求缓存在内存中。当rdb快照生成之后会发送slave实例,slave用这个rdb快照放到自己的数据目录下并加载到内存中。

    3:master生成快照发送给slave期间缓存在内存中的命令,会再次发送给slave。

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

    主从复制(全量复制)流程图

    数据部分复制

    当master和slave断开重连之后,一般都会对整份数据进行复制。但是从redis2.8版本开始,redis改用可以支持部分数据复制的命令PSYNC去master同步数据,slave与master能够在网络连接断开重连后只进行部分数据复制(断点续传)。

    master会在其内存中创建一个复制数据用的缓存队列,缓存最近一段时间的数据,master和它所有的slave都维护了复制的数据下标offset和master的进程id,因此,当网络连接断开后,slave会请求master继续进行未完成的复制,从所记录的数据下标开始。如果master进程id变化了,或者从节点数据下标offset太旧了,已经不在master的缓存队列里面了,那么将会进行一次全量的数据复制。

    主从复制(部分复制,断点续传)流程图:

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

     哨兵高可用架构

     sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。哨兵模式架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过sentinel代理访问redis主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis主节点通知给client端(这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)

    哨兵架构搭建步骤:

    从上面架构图可以看出,哨兵集群只要主从集群的的基础上搭建一个哨兵集群就可以了。

    哨兵实例使用的是sentinel.conf

    1: 复制一份sentinel.conf 为sentinel-26379.conf

    3:修改如下配置

    1. port 26379 #哨兵实例也有端口号
    2. daemonize yes
    3. pidfile "/var/run/redis‐sentinel‐26379.pid"
    4. logfile "26379.log"
    5. dir "/usr/local/redis‐5.0.3/data"
    6. #sentinel monitor <master-name> <ip> <redis-port> <quorum>
    7. # quorum是一个数字,指明当有多少个sentinel认为一个master失效时,
    8. # 一般是seentinel实例总数/2 +1
    9. #这里打算起三个sentinel实例 ,mymaster只是一个集群名字,可以自定义
    10. sentinel monitor mymaster 127.0.0.1 6379 2

      4:启动哨兵实例

    src/redis-sentinel ./conf/sentinel-26270.conf

    按照上面的方式再启动两个哨兵实例

    启动完成,有三个redis服务实例,三个sentinel实例。

     使用:src/redis-cli -p 6380 进入到6380的这个redis客户端,执行info命令

     展示的信息里面有一项Replication,

    可以看到当前这个实例的角色是slave,主节点是6379端口的实例。

    src/redis-cli -p 26380 去看下哨兵实例的信息

    在最后一行显示哨兵的实例数只有一个,并没有其它哨兵节点的信息。说明哨兵之间并没有发生通信,这样就不会发生选举事情。 

    至于为什么出现这样的情况,和哨兵使用的配置文件有关,这边启动的三个哨兵实例都是直接复制文件来的,里面有个关键配置:sentinel myid 来标识不同哨兵实例,三个实例是同一个值,这里把它都注释掉重新启动哨兵实例,让其自动生成。

     这样启动之后,在任一个哨兵配置文件的最后可以看到其它哨兵的信息:

     在SpringBoot项目中访问redis操作实践下:

    引入依赖:

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-data-redis</artifactId>
    4. </dependency>
    5. <dependency>
    6. <groupId>org.apache.commons</groupId>
    7. <artifactId>commons-pool2</artifactId>
    8. </dependency>

    相关yml配置:

    1. spring:
    2. redis:
    3. database: 0
    4. timeout: 3000 #read time out
    5. connect-timeout: 3000 #connection time out
    6. sentinel:
    7. master: mymaster #哨兵conf中自定义的
    8. nodes: 127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381 #哨兵节点
    9. lettuce:
    10. pool: #连接池
    11. max-active: 100
    12. max-idle: 50
    13. min-idle: 10
    14. max-wait: 1000
    15. server:
    16. port: 8980
    1. @GetMapping("/test")
    2. public void testRedis() throws InterruptedException {
    3. int i = 0;
    4. while (true) {
    5. try{
    6. stringRedisTemplate.opsForValue().set("key:" + i, i + "", 100, TimeUnit.SECONDS);
    7. i++;
    8. }catch (Exception ex){
    9. log.info("出现了异常: cause: {}",ex.getCause());
    10. }
    11. Thread.sleep(4000L);
    12. }
    13. }

    刚开始的时候,哨兵和主从集群是正常的,可以在redis实例的客户端都能看到放入的数据,当我们把redis的Master节点Kill掉之后,程序就会报错,因为sentinel实例选举新的master节点需要时间,这段时间本地还是尝试连接之前的master节点,所以会连接失败。

    1. 2022-06-30 22:20:30.401 WARN 49016 --- [oEventLoop-4-10] i.l.core.protocol.ConnectionWatchdog : Cannot reconnect to [127.0.0.1:6379]: Connection refused: no further information: /127.0.0.1:6379
    2. 2022-06-30 22:20:31.149 INFO 49016 --- [nio-8980-exec-1] c.z.m.demo.controller.RedisController : 出现了异常: cause: {}
    3. io.lettuce.core.RedisCommandTimeoutException: Command timed out after 3 second(s)

     等到sentinel选举出来新的master节点之后,会重新连接上:Reconnected to 127.0.0.1:6380

    1. 2022-06-30 22:20:34.578 INFO 49016 --- [xecutorLoop-1-7] i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was 127.0.0.1:6379
    2. 2022-06-30 22:20:34.727 INFO 49016 --- [oEventLoop-4-12] i.l.core.protocol.ReconnectionHandler : Reconnected to 127.0.0.1:6380

  • 相关阅读:
    mac 安装pandas教程并验证是否成功安装
    服务器硬件基础知识
    宁德时代定增450亿:高瓴认购30亿 曾毓群仍控制23%股权
    Node.js 实战 第1章 欢迎进入Node.js 的世界 1.4 Node 自带的工具 1.4.3 调试器
    《大数据:互联网大规模数据挖掘与分布式处理》(第2版)习题6.1.1-6.1.3解析
    javabasic
    vue、全局前置守卫
    阿里云基于边缘云业务场景的 “前端智能化” 实践
    分布式调度Zookeeper常用Shell命令【云原生】
    nodejs+vue电影在线预定与管理系统的设计与实现-微信小程序-安卓-python-PHP-计算机毕业设计
  • 原文地址:https://blog.csdn.net/A7_A8_A9/article/details/125384098