目录

  • 架构图
  • 1.为什么需要哨兵架构
  • 2.redis哨兵架构搭建
  • 搭建哨兵服务
  • 踩坑记录
  • redis主从自动切换自动切换
  • 3.Java代码连接
  • 哨兵的连接代码-main方法方式-Jedis类
  • Reids连接-springboot方式-RedisTemplate类


架构图

redis哨兵集群 redis哨兵集群信息查看_redis


sentinel[ˈsentɪnl]哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。

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

sentinel也是redis实例;
整个哨兵集群都在监听reids的主机和所有从机,从而判断某个机器是否宕机等问题;
当哨兵发现主节点宕机,会自动选择某个从节点当做主节点;

1.为什么需要哨兵架构

如果没有哨兵架构,那么当主节点挂了的时候,需要运维人员手动将某个从节点设置为主节点,还需要修改IP等其他操作。

2.redis哨兵架构搭建

按照上面架构图来搭建架构:一个主机、两个从机、三个哨兵。

搭建一个主机两个从机

1.之前自己电脑上面已经存在6379、6380两个reids实例,且6380是作为从节点的。现在,我们再增加一个6381的从节点:

步骤:参考本篇----二、Redis主从架构1.redis主从架构搭建,配置从节点步骤

redis哨兵集群 redis哨兵集群信息查看_缓存_02

搭建哨兵服务

哨兵服务也是redis实例;
一般的策略是配置3个或者5个哨兵(奇数),此处我们配置三个哨兵;

1、复制一份sentinel.conf文件到我们统一的config目录下,原生的redis目录下就存在sentinel.conf
cp sentinel.conf config/sentinel-26379.conf

2、将相关配置修改为如下值:
  port 26379
  daemonize yes
  pidfile "/var/run/redis-sentinel-26379.pid" # 不需要创建该文件,文件会自动生成
  logfile "26379.log" # 不需要创建该文件,文件会自动生成
  dir "/opt/redis-6.2.2/data" # 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.43.10 6379 2 #mymaster这个名字随便取,客户端访问时会用到

3、自己再配置两个sentinel,端口26380和26381,注意上述配置文件里的对应数字都要修改
   复制命令: cp sentinel.conf sentinel-26380.conf 
   复制命令: cp sentinel.conf sentinel-26381.conf 
   修改的地方:port、pidfile、logfile、如果有sentinel myid这一行删掉(踩坑。知道为啥删吗?)

4、启动sentinel哨兵实例
src/redis-sentinel config/sentinel-26379.conf
src/redis-sentinel config/sentinel-26380.conf
src/redis-sentinel config/sentinel-26381.conf

5、ps -ef|grep redis查看服务是否开启

6、启动指定端口的redis服务,连接哨兵服务器。查看sentinel的info信息.
src/redis-cli -p 26379
127.0.0.1:26379>info
可以看到Sentinel的info里已经识别出了redis的主从

启动三个哨兵服务:

redis哨兵集群 redis哨兵集群信息查看_java_03

查看哨兵服务是否开启:

redis哨兵集群 redis哨兵集群信息查看_数据库_04

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

踩坑记录

redis哨兵集群 redis哨兵集群信息查看_java_05


解决Redis哨兵集群哨兵之间无法感应问题

redis哨兵集群 redis哨兵集群信息查看_java_06

redis主从自动切换自动切换

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

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  #代表感知到的其它哨兵节点

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

sentinel monitor mymaster 192.168.0.60 6380 2

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

3.Java代码连接

哨兵的连接代码-main方法方式-Jedis类

该代码模拟的是:Java代码的redis客户端不会直接与redis主机连接,而是通过哨兵连接redis的主机。

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.43.10",26379).toString());
        sentinels.add(new HostAndPort("192.168.43.10",26380).toString());
        sentinels.add(new HostAndPort("192.168.43.10",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", "zhuge"));
            System.out.println(jedis.get("sentinel"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
            if (jedis != null)
                jedis.close();
        }
    }
}

redis哨兵集群 redis哨兵集群信息查看_缓存_07

Reids连接-springboot方式-RedisTemplate类

springboot项目更多的采用RedisTemplate类连接redis,而不是采用Jedis。

哨兵的Spring Boot整合Redis连接代码见示例项目:redis-sentinel-cluster
1、引入相关依赖:

<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项目核心配置:

server:
  port: 8080

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

访问代码:

@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);
            }
        }
    }
}

过了十几秒后,主从开始切换;

重新启动6379服务,启动6379客户端,执行info命令,发现现在redis主机成了6380,并且redis主节、从机、所有的哨兵都会自动修改同步主机配置数据(conf文件中):

redis哨兵集群 redis哨兵集群信息查看_缓存_08