• 04-Redis哨兵高可用架构


    上一篇:03-Redis主从架构

    架构说明
    在这里插入图片描述

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

    redis哨兵架构搭建步骤:

    1、复制一份sentinel.conf文件
    cp sentinel.conf sentinel-26379.conf
    
    2、将相关配置修改为如下值:
    port 26379
    daemonize yes
    pidfile "/var/run/redis-sentinel-26379.pid"
    logfile "26379.log"
    dir "/usr/local/redis-5.0.3/data"
    # 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这个名字随便取,客户端访问时会用到
    
    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,端口2638026381,注意上述配置文件里的对应数字都要修改
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    sentinel集群都启动完毕后,会将哨兵集群的元数据信息写入所有sentinel的配置文件里去(追加在文件的最下面),我们查看下如下配置文件sentinel-26379.conf,如下所示:

    sentinel known-replica mymaster 192.168.0.60 6380 #代表redis主节点的从节点信息
    sentinel known-replica mymaster 192.168.0.60 6381 #代表redis主节点的从节点信息
    sentinel known-sentinel mymaster 192.168.0.60 26380 52d0a5d70c1f90475b4fc03b6ce7c3c56935760f  #代表感知到的其它哨兵节点
    sentinel known-sentinel mymaster 192.168.0.60 26381 e9f530d3882f8043f76ebb8e1686438ba8bd5ca6  #代表感知到的其它哨兵节点
    
    • 1
    • 2
    • 3
    • 4

    当redis主节点如果挂了,哨兵集群会重新选举出新的redis主节点,同时会修改所有sentinel节点配置文件的集群元数据信息,比如6379的redis如果挂了,假设选举出的新主节点是6380,则sentinel文件里的集群元数据信息会变成如下所示:
    sentinel known-replica mymaster 192.168.0.60 6379 #代表主节点的从节点信息

    sentinel known-replica mymaster 192.168.0.60 6379 #代表主节点的从节点信息
    sentinel known-replica mymaster 192.168.0.60 6381 #代表主节点的从节点信息
    sentinel known-sentinel mymaster 192.168.0.60 26380 52d0a5d70c1f90475b4fc03b6ce7c3c56935760f  #代表感知到的其它哨兵节点
    sentinel known-sentinel mymaster 192.168.0.60 26381 e9f530d3882f8043f76ebb8e1686438ba8bd5ca6  #代表感知到的其它哨兵节点
    
    • 1
    • 2
    • 3
    • 4

    同时还会修改sentinel文件里之前配置的mymaster对应的6379端口,改为6380

    sentinel monitor mymaster 192.168.0.60 6380 2
    
    • 1

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

    哨兵的Jedis连接代码:

    public class JedisSentinelTest {
        public static void main(String[] args) throws IOException {
    
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(20);
            config.setMaxIdle(10);
            config.setMinIdle(5);
    
            String masterName = "mymaster";
            Set<String> sentinels = new HashSet<String>();
            sentinels.add(new HostAndPort("192.168.0.60",26379).toString());
            sentinels.add(new HostAndPort("192.168.0.60",26380).toString());
            sentinels.add(new HostAndPort("192.168.0.60",26381).toString());
            //JedisSentinelPool其实本质跟JedisPool类似,都是与redis主节点建立的连接池
            //JedisSentinelPool并不是说与sentinel建立的连接池,而是通过sentinel发现redis主节点并与其建立连接
            JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, config, 3000, null);
            Jedis jedis = null;
            try {
                jedis = jedisSentinelPool.getResource();
                System.out.println(jedis.set("sentinel", "gwx"));
                System.out.println(jedis.get("sentinel"));
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
                if (jedis != null)
                    jedis.close();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    哨兵的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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    springboot项目核心配置:

    server:
      port: 8080
    
    spring:
      redis:
        database: 0
        timeout: 3000
        sentinel:    #哨兵模式
          master: mymaster #主服务器所在集群名称
         nodes: 192.168.0.60:26379,192.168.0.60:26380,192.168.0.60:26381
       lettuce:
          pool:
            max-idle: 50
            min-idle: 10
            max-active: 100
            max-wait: 1000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    访问代码:

    @RestController
    public class IndexController {
    
        private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
    
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
    
        /**
         * 测试节点挂了哨兵重新选举新的master节点,客户端是否能动态感知到
         * 新的master选举出来后,哨兵会把消息发布出去,客户端实际上是实现了一个消息监听机制,
         * 当哨兵把新master的消息发布出去,客户端会立马感知到新master的信息,从而动态切换访问的masterip
         *
         * @throws InterruptedException
         */
        @RequestMapping("/test_sentinel")
        public void testSentinel() throws InterruptedException {
            int i = 1;
            while (true){
                try {
                    stringRedisTemplate.opsForValue().set("zhuge"+i, i+"");
                    System.out.println("设置key:"+ "zhuge" + i);
                    i++;
                    Thread.sleep(1000);
                }catch (Exception e){
                    logger.error("错误:", e);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    StringRedisTemplate与RedisTemplate详解
    spring 封装了 RedisTemplate 对象来进行对redis的各种操作,它支持所有的 redis 原生的 api。在RedisTemplate中提供了几个常用的接口方法的使用,分别是:

    private ValueOperations<K, V> valueOps;
    private HashOperations<K, V> hashOps;
    private ListOperations<K, V> listOps;
    private SetOperations<K, V> setOps;
    private ZSetOperations<K, V> zSetOps;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    RedisTemplate中定义了对5种数据结构操作
    redisTemplate.opsForValue();//操作字符串

    redisTemplate.opsForValue();//操作字符串
    redisTemplate.opsForHash();//操作hash
    redisTemplate.opsForList();//操作list
    redisTemplate.opsForSet();//操作set
    redisTemplate.opsForZSet();//操作有序set
    
    • 1
    • 2
    • 3
    • 4
    • 5

    StringRedisTemplate继承自RedisTemplate,也一样拥有上面这些操作。
    StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
    RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。

    Redis客户端命令对应的RedisTemplate中的方法列表:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    理解字符串常量池(JVM)
    vue3脚手架运行各种报错汇总(持续收集)
    配置中心和注册中心——Nacos
    互联网医院App开发:构建医疗服务的技术指南
    【考研】数据结构考点——归并排序
    HarmonyOS/OpenHarmony应用开发-DataAbility开发体验
    Spring MVC 中文文档
    Stream流
    Mac下cmake使用Android编译
    根据java文法生成对应的词法分析器Content description
  • 原文地址:https://blog.csdn.net/weixin_40461030/article/details/132837255