Redis-19Redis哨兵Sentinel模式-Centos6.5上3台主机1主2从3哨兵的配置及通过代码访问哨兵

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
云防火墙,500元 1000GB
简介: Redis-19Redis哨兵Sentinel模式-Centos6.5上3台主机1主2从3哨兵的配置及通过代码访问哨兵

概述



Redis主从模式当主服务器右机后,需要手动把一台从服务器切换为主从服务器,这就需要人工干预,既费时费力,会造成一段时间内服务不可用,不推荐使用。 可以使用哨兵模式或者集群模式。 这里我们来探讨哨兵模式。


Redis 可以存在多台服务器,并且实现了主从复制的功能。哨兵模式是一种特殊的模式,首先 Redis 提供了哨兵的命令,哨兵是一个独立 的进程,作为进程,它会独立运行。原理是哨兵通过发送命令, 等待 Redis 服务器响应,从而监控运行的多个 Redis 实例。


这里哨兵有两个作用


通过发送命令,让 Redis 服务器返回监测其运行状态,包括主服务器和从服务器。

当 哨兵监测到 master宕机, 会自动将 slave 切换成 master,然后通过发布订阅模式通知到其他的从服务器,修改配置文件,让它们切换主机 。

只是现实中一个哨兵进程对 Redis 服务器进行监控,也可能出现问题,为了处理这个问题,还可以使用多个哨兵的监控,而各个哨兵之间还会相互监控,这样就变为了多个哨兵模式。多个哨兵不仅监控各个 Redis 服务器,而且哨兵之间互相监控 , 看看哨兵们是否还“活 ” 着。 如下图


20180929165937332.png


故障切换( failover)的过程:


假设主服务器岩机,哨兵 1 先监测到这个结果,当时系统并不会马上进行 failover 操作 ,而仅仅是哨兵1 主观地认为主机己经不可用,这个现象被称为主观下线。【SDOWN】

当后面的哨兵监测也监测到了主服务器不可用 , 并且有了 一定数量的哨兵认为主服务器不可用,那么哨兵之间就会形成一次投票,投票的结果由一个哨兵发起,进行 failover 操作,在 failover 操作的过程中切换成功后,就会通过发布订阅方式,让各个哨兵把自己监控的服务器实现切换主机 , 这个过程被称为客观下线【ODOWN】

这样对于客户端而言, 一切都是透明的 。


环境


redis版本: 4.0.11

操作系统: Centos6.5

主机信息 :


image.png


Sentinel环境搭建


如果没有足够的主机,那我们就通过VMware来搭建多个主机模拟下集群环境

参考我博文 VMware-使用VMware在本地搭建多个CentOS虚机

2018092917231331.png


同时需要在3台主机上部署Redis,参考我博 Redis-02Redis在linux下的安装及常见问题

20180929172328383.png


完成上面两步之后 ,就可以着手调整部署了


防火墙策略的调整

确保redis和哨兵进程的端口,在防火墙上开放。


redis的默认6379端口,在防火墙上开放,可以在本地通过RedisDeskTopManager来登录

哨兵的默认26379端口,在防火墙上开放,确保哨兵之间的通信。


这里为了方便起见,选择了关闭防火墙。


CentOS6.5永久关闭防火墙


使用root用户


[root@artisan ~]# service iptables stop
[root@artisan ~]# service iptables status
iptables: Firewall is not running
[root@artisan ~]# chkconfig iptables off
[root@artisan ~]# 

配置修改【最少修改】 (Redis集群带访问密码)

这里说的是Redis集群配置了访问密码的场景。

Redis 的主服务器的配置修改

登录192.168.31.66主机


仅说需要调整的地方,未说明的地方保持默认即可。

#使得 Redis 服务器可以跨网络访问
bind  0.0.0.0
#设置密码
requirepass  artisan
#主服务器密码
masterauth  artisan

因为发生切换时预先设定的master会变成slave,下次再发生故障的时候,如果没有masterauth artisan会失败。

为了方便观察日志,我们这里 daemonize no 暂时没有修改。


Redis 的从服务器的配置修改

#使得 Redis 服务器可以跨网络访问
bind  0.0.0.0
#设置密码
requirepass  artisan
#指定主服务器,注意:有关 slaveof 的配置只是配置从服务器,而主服务器不需要配置
slaveof 192.168.31.56 637
#主服务器密码 , 注意:有关 slaveof 的配置只是配置从服务器,而主服务器不需要配置
masterauth  artisan


上述内容主要是配置 Redis 服务器,从服务器比主服务器多一个 slaveof 的配置和密码 ,这里配置的 bind 使得 Redis 服务器可以跨网段访问 。 而对于外部的访问还需要提供密码,因此还提供了 requirepass 的配置,用以配置密码 ,这样就配置完了 3 台服务器 。


哨兵sentinel.conf 的配置


配置 3 个哨 兵 , 每一个哨兵的配置都是一样的 ,在 Redis 安装目录下可以找到sentinel.conf 文件,然后对其进行修改

下面对 3 个哨兵的这个文件作出修改,同样也是在原有的基础上进行修改,仅仅列出改动的地方,如下所示

# 禁止保护模式
protected-mode no
# 配置监听的主服务器,这里 sentinel monitor 代表监控 ,
# mymaster 代表服务器名称,可以自定义
# 192.168.31.66 代表监控的主服务器
# 6379 代表端口
# 2 代表只有两个或者两个以上的哨兵认为主服务器不可用的时候,才会做故障切换操作
sentinel monitor mymaster 192.168.31.66  6379 2
# sentinel auth-pass 定义服务的密码
# mymaster 服务名称
# artisan Redis 服务器密码
sentinel auth-pass mymaster artisan 


关闭了保护模式,以便测试。 sentinel monitor 是配置一个哨兵主要的内 容 , 首先是自定义服务名称 mymaster,然后映射服务器和端口 。最后的 2 是代表当存在两个或者两个以上的哨兵投票认可当前主服务器不可用后 ,才会进行故障切换,这样可以降低因出错而切换主服务器的概率。 sentinel auth-pass 用于配置服务名称及其密码。


启动顺序


首先是主机 192.168.31.66的 Redis 服务进程 ,然后启动从机的服务进程,最后启动 3 个哨兵的服务进程

哨兵进程启动命令,指定配置文件

./redis-sentinel  ../etc/sentinel.conf


测试


写这篇博客的时候,已经模拟过一次主节点故障了,主节点已经被为了 192.168.31.56了 . 所以接着这里继续来看下。


首先启动 Redis主服务器的Redis服务 – > Redis从服务器的Redis服务(2个)。


然后启动 每台主机上对应的哨兵进程


56主机

[redis@artisan bin]$ ./redis-sentinel ../etc/sentinel.conf 
2128:X 30 Sep 02:07:23.601 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2128:X 30 Sep 02:07:23.602 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=2128, just started
2128:X 30 Sep 02:07:23.602 # Configuration loaded
2128:X 30 Sep 02:07:23.607 * Increased maximum number of open files to 4096 (it was originally set to 1024).
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 2128
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               
2128:X 30 Sep 02:07:23.611 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2128:X 30 Sep 02:07:23.611 # Sentinel ID is db0d6183683b97f001514c53e36ceabd2bcf2bb4
2128:X 30 Sep 02:07:23.611 # +monitor master mymaster 192.168.31.56 6379 quorum 2

66主机

[redis@artisan bin]$ ./redis-sentinel ../etc/sentinel.conf 
2696:X 30 Sep 02:06:52.261 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2696:X 30 Sep 02:06:52.261 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=2696, just started
2696:X 30 Sep 02:06:52.261 # Configuration loaded
2696:X 30 Sep 02:06:52.262 * Increased maximum number of open files to 4096 (it was originally set to 1024).
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 2696
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               
2696:X 30 Sep 02:06:52.269 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2696:X 30 Sep 02:06:52.269 # Sentinel ID is 06f62ff2d7739c81c83bbca1864a6765ca67ab36
2696:X 30 Sep 02:06:52.269 # +monitor master mymaster 192.168.31.56 6379 quorum 2


176主机

[redis@artisan ~]$ cd redis/redis-4.0.11/bin/
[redis@artisan bin]$ ./redis-sentinel ../etc/sentinel.conf 
2211:X 30 Sep 02:07:44.182 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2211:X 30 Sep 02:07:44.182 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=2211, just started
2211:X 30 Sep 02:07:44.182 # Configuration loaded
2211:X 30 Sep 02:07:44.183 * Increased maximum number of open files to 4096 (it was originally set to 1024).
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 2211
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               
2211:X 30 Sep 02:07:44.188 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2211:X 30 Sep 02:07:44.188 # Sentinel ID is e95574e02478706f3cd27b8022340523d3a09e6d
2211:X 30 Sep 02:07:44.188 # +monitor master mymaster 192.168.31.56 6379 quorum 2


然后停掉Master 56的redis-server进程,观察哨兵日志的选举

56的哨兵输出

2128:X 30 Sep 02:09:37.657 # +sdown master mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:37.709 # +odown master mymaster 192.168.31.56 6379 #quorum 3/2
2128:X 30 Sep 02:09:37.710 # +new-epoch 2
2128:X 30 Sep 02:09:37.710 # +try-failover master mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:37.721 # +vote-for-leader db0d6183683b97f001514c53e36ceabd2bcf2bb4 2
2128:X 30 Sep 02:09:37.730 # e95574e02478706f3cd27b8022340523d3a09e6d voted for db0d6183683b97f001514c53e36ceabd2bcf2bb4 2
2128:X 30 Sep 02:09:37.746 # 06f62ff2d7739c81c83bbca1864a6765ca67ab36 voted for db0d6183683b97f001514c53e36ceabd2bcf2bb4 2
2128:X 30 Sep 02:09:37.777 # +elected-leader master mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:37.777 # +failover-state-select-slave master mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:37.861 # +selected-slave slave 192.168.31.176:6379 192.168.31.176 6379 @ mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:37.861 * +failover-state-send-slaveof-noone slave 192.168.31.176:6379 192.168.31.176 6379 @ mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:37.961 * +failover-state-wait-promotion slave 192.168.31.176:6379 192.168.31.176 6379 @ mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:38.822 # +promoted-slave slave 192.168.31.176:6379 192.168.31.176 6379 @ mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:38.822 # +failover-state-reconf-slaves master mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:38.879 * +slave-reconf-sent slave 192.168.31.66:6379 192.168.31.66 6379 @ mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:39.817 * +slave-reconf-inprog slave 192.168.31.66:6379 192.168.31.66 6379 @ mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:39.818 * +slave-reconf-done slave 192.168.31.66:6379 192.168.31.66 6379 @ mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:39.891 # -odown master mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:39.891 # +failover-end master mymaster 192.168.31.56 6379
2128:X 30 Sep 02:09:39.891 # +switch-master mymaster 192.168.31.56 6379 192.168.31.176 6379
2128:X 30 Sep 02:09:39.894 * +slave slave 192.168.31.66:6379 192.168.31.66 6379 @ mymaster 192.168.31.176 6379
2128:X 30 Sep 02:09:39.895 * +slave slave 192.168.31.56:6379 192.168.31.56 6379 @ mymaster 192.168.31.176 6379
2128:X 30 Sep 02:10:09.920 # +sdown slave 192.168.31.56:6379 192.168.31.56 6379 @ mymaster 192.168.31.176 6379


+sdown 表示哨兵主观认为数据库下线

+odown 表示哨兵客观认为数据库下线

+try-failover 表示哨兵开始进行故障恢复

+failover-end 表示哨兵完成故障修复,其中包括了领头哨兵的选举、备选从数据库的选择等等较为复杂的过程

+switch-master表示主数据库从56服务器迁移到176服务器

+slave列出了新的主数据库的2个从数据库,而哨兵并没有彻底清除56服务器的实力信息,这是因为停止的实例有可能会在将来恢复,哨兵会让其重新加入进来


66的哨兵输入

2696:X 30 Sep 02:09:21.731 # +sdown master mymaster 192.168.31.56 6379
2696:X 30 Sep 02:09:21.848 # +new-epoch 2
2696:X 30 Sep 02:09:21.853 # +vote-for-leader db0d6183683b97f001514c53e36ceabd2bcf2bb4 2
2696:X 30 Sep 02:09:22.838 # +odown master mymaster 192.168.31.56 6379 #quorum 3/2
2696:X 30 Sep 02:09:22.838 # Next failover delay: I will not start a failover before Sun Sep 30 02:15:22 2018
2696:X 30 Sep 02:09:22.990 # +config-update-from sentinel db0d6183683b97f001514c53e36ceabd2bcf2bb4 192.168.31.56 26379 @ mymaster 192.168.31.56 6379
2696:X 30 Sep 02:09:22.990 # +switch-master mymaster 192.168.31.56 6379 192.168.31.176 6379
2696:X 30 Sep 02:09:22.993 * +slave slave 192.168.31.66:6379 192.168.31.66 6379 @ mymaster 192.168.31.176 6379
2696:X 30 Sep 02:09:22.993 * +slave slave 192.168.31.56:6379 192.168.31.56 6379 @ mymaster 192.168.31.176 6379
2696:X 30 Sep 02:09:53.008 # +sdown slave 192.168.31.56:6379 192.168.31.56 6379 @ mymaster 192.168.31.176 6379

176的哨兵输出

2211:X 30 Sep 02:09:45.243 # +sdown master mymaster 192.168.31.56 6379
2211:X 30 Sep 02:09:45.336 # +new-epoch 2
2211:X 30 Sep 02:09:45.339 # +vote-for-leader db0d6183683b97f001514c53e36ceabd2bcf2bb4 2
2211:X 30 Sep 02:09:45.341 # +odown master mymaster 192.168.31.56 6379 #quorum 2/2
2211:X 30 Sep 02:09:45.341 # Next failover delay: I will not start a failover before Sun Sep 30 02:15:45 2018
2211:X 30 Sep 02:09:46.492 # +config-update-from sentinel db0d6183683b97f001514c53e36ceabd2bcf2bb4 192.168.31.56 26379 @ mymaster 192.168.31.56 6379
2211:X 30 Sep 02:09:46.492 # +switch-master mymaster 192.168.31.56 6379 192.168.31.176 6379
2211:X 30 Sep 02:09:46.493 * +slave slave 192.168.31.66:6379 192.168.31.66 6379 @ mymaster 192.168.31.176 6379
2211:X 30 Sep 02:09:46.494 * +slave slave 192.168.31.56:6379 192.168.31.56 6379 @ mymaster 192.168.31.176 6379
2211:X 30 Sep 02:10:16.557 # +sdown slave 192.168.31.56:6379 192.168.31.56 6379 @ mymaster 192.168.31.176 6379

结果是选举了 176作为Master

通过客户端也可以看到176的role为master


20180929183527594.png


使用JavaAPI 访问 Redis Sentinel集群


我们先把停掉的56起来,现在master是176主机,56起来之后,肯定是slave状态了。


20180929183857376.png


为了测试数据的干净,我们现在master节点上flushdb清空keys,redis会自动同步到到另外两个slave节点。


如果在slave机器上执行flushdb,会抛出如下异常

"READONLY You can't write against a read only slave."


在 Java 中使用哨兵模式 ,加入关于哨兵的信息即可,非常简单,如下

package com.artisan.redis.sentinel;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
public class JavaRedisSentinel {
  public static void main(String[] args) {
    // 连接池配置
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxIdle(50);
    jedisPoolConfig.setMaxTotal(100);
    jedisPoolConfig.setMaxWaitMillis(2000);
    // 哨兵信息
    Set<String> sentinelsSet = new HashSet<String>(Arrays.asList("192.168.31.66:26379", "192.168.31.56:26379", "192.168.31.176:26379"));
    // 创建连接池
    JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster", sentinelsSet, jedisPoolConfig, "artisan");
    // 获取客户端
    Jedis jedis = sentinelPool.getResource();
    // 执行指令测试下
    jedis.set("artisan_key", "artisan_value");
    String result = jedis.get("artisan_key");
    System.out.println("artisan_key对应的value为:" + result);
  }
}


运行:

九月 29, 2018 6:42:10 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
九月 29, 2018 6:42:10 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 192.168.31.176:6379, starting Sentinel listeners...
九月 29, 2018 6:42:10 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.31.176:6379
artisan_key对应的value为:artisan_value



划重点:Redis master running at 192.168.31.176:6379

去redis中查看,三个节点中均存在这个key

20180929184320812.png


20180929184328586.png

20180929184337604.png


停掉master的redis-server ,然后再次操作


为了验证哨兵的作用,我们可以把主机上的 Redis 服务器关闭 , 马上运行,你

就可以发现报错 , 那倒不是因为哨兵失效导致的,而是因为 Redis 哨兵默认超时 3 分钟后才会进行投票切换主机,等超过 3 分钟后再进行测试


输出

九月 29, 2018 6:45:05 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
九月 29, 2018 6:45:05 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 192.168.31.56:6379, starting Sentinel listeners...
九月 29, 2018 6:45:05 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.31.56:6379
artisan_key对应的value为:artisan_value

划重点: Redis master running at 192.168.31.56:6379


从日志可以看到 , 我们实际使用的是 192.168.31.56 服务器,这是因为在192.168.31.176服务器不可用后 , 哨兵经过投票切换为 192.168.31.56服务器,通过这样的自动切换就保证服务持续稳定运行了。


使用Spring访问Redis Sentinel集群

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd">
    <context:property-placeholder location="classpath:redis/redis.properties" />
    <!--2,注意新版本2.3以后,JedisPoolConfig的property name,不是maxActive而是maxTotal,而且没有maxWait属性,建议看一下Jedis源码或百度。 -->
    <!-- redis连接池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!--最大空闲数 -->
        <property name="maxIdle" value="${redis.maxIdle}" />
        <!--连接池的最大数据库连接数 -->
        <property name="maxTotal" value="${redis.maxTotal}" />
        <!--最大建立连接等待时间 -->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟) -->
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />
        <!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 -->
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />
        <!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 -->
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />
      <property name="testOnBorrow" value="true"></property>
    <property name="testOnReturn" value="true"></property>
    <property name="testWhileIdle" value="true"></property>
    </bean>
  <!-- 键值序列化器设置为String 类型 -->
  <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
  <!-- jdk序列化器,可保存对象 -->
  <bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
  <!-- 哨兵配置 -->
  <bean id="sentinelConfig" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <!-- 服务名称 -->
    <property name="master">
      <bean class="org.springframework.data.redis.connection.RedisNode">
        <property name="name" value="mymaster"/>
      </bean>
    </property>
    <!-- 哨兵服务 IP 和端口  -->
    <property name="sentinels">
      <set>
        <bean class="org.springframework.data.redis.connection.RedisNode">
          <constructor-arg name="host" value="192.168.31.56"/>
          <constructor-arg name="port" value="26379"/>
        </bean>
        <bean class="org.springframework.data.redis.connection.RedisNode">
          <constructor-arg name="host" value="192.168.31.66"/>
          <constructor-arg name="port" value="26379"/>
        </bean>
        <bean class="org.springframework.data.redis.connection.RedisNode">
          <constructor-arg name="host" value="192.168.31.176"/>
          <constructor-arg name="port" value="26379"/>
        </bean>
      </set>
    </property>
  </bean>
  <!--redis连接工厂 -->
    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        destroy-method="destroy">
        <constructor-arg name="sentinelConfig" ref="sentinelConfig"/>
        <constructor-arg name="poolConfig" ref="jedisPoolConfig"/>
        <property name="password" value="artisan"/>
    </bean>
  <!-- redis template definition -->
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
    p:connection-factory-ref="jedisConnectionFactory"
    p:keySerializer-ref="stringRedisSerializer"
    p:defaultSerializer-ref="stringRedisSerializer"
    p:valueSerializer-ref="jdkSerializationRedisSerializer">
  </bean>
</beans>
package com.artisan.redis.sentinel;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
public class SpringRedisSentinel {
  @SuppressWarnings({ "unchecked", "rawtypes", "resource" })
  public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring/spring-redis-sentinel.xml");
    RedisTemplate redisTemplate = ctx.getBean(RedisTemplate.class);
    String retVaule = (String) redisTemplate.execute((RedisOperations ops) -> {
      ops.boundValueOps("artisan_k").set("artisan_v");
      String value = (String) ops.boundValueOps("artisan_k").get();
      return value;
    });
    System.out.println(retVaule);
  }
}

先把停掉的176起来,确保集群正常 .执行应用程序

INFO : org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@73a8dfcc: startup date [Sat Sep 29 19:13:09 CST 2018]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [spring/spring-redis-sentinel.xml]
九月 29, 2018 7:13:09 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
九月 29, 2018 7:13:10 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 192.168.31.56:6379, starting Sentinel listeners...
九月 29, 2018 7:13:10 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.31.56:6379
artisan_v


Redis master running at 192.168.31.56:6379

停掉56 ,马上访问

INFO : org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@73a8dfcc: startup date [Sat Sep 29 19:15:27 CST 2018]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [spring/spring-redis-sentinel.xml]
九月 29, 2018 7:15:28 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
九月 29, 2018 7:15:28 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 192.168.31.56:6379, starting Sentinel listeners...
九月 29, 2018 7:15:28 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.31.56:6379
Exception in thread "main" org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:286)
  at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:469)
  at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:132)
  at org.springframework.data.redis.core.RedisConnectionUtils.bindConnection(RedisConnectionUtils.java:70)
  at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:250)
  at com.artisan.redis.sentinel.SpringRedisSentinel.main(SpringRedisSentinel.java:15)
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  at redis.clients.util.Pool.getResource(Pool.java:53)
  at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:209)
  at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:17)
  at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:276)
  ... 5 more
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect
  at redis.clients.jedis.Connection.connect(Connection.java:207)
  at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:93)
  at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1767)
  at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:106)
  at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:868)
  at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435)
  at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
  at redis.clients.util.Pool.getResource(Pool.java:49)
  ... 8 more
Caused by: java.net.ConnectException: Connection refused: connect
  at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
  at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
  at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
  at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
  at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
  at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
  at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
  at java.net.Socket.connect(Socket.java:589)
  at redis.clients.jedis.Connection.connect(Connection.java:184)
  ... 15 more


等集群选举完后,再次访问

INFO : org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@73a8dfcc: startup date [Sat Sep 29 19:16:02 CST 2018]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [spring/spring-redis-sentinel.xml]
九月 29, 2018 7:16:03 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
九月 29, 2018 7:16:03 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 192.168.31.176:6379, starting Sentinel listeners...
九月 29, 2018 7:16:03 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.31.176:6379
artisan_v



Redis master running at 192.168.31.176:6379

切换到了176,确保了服务的可用。


哨兵模式的其他配置顶


image.png


sentinel down-after-milliseconds 配置项只是一个哨兵在超过其指定的毫秒数依 旧没有得到回答消息后,会自己认为主机不可用。对于其他哨兵而言,并不会认为主机不可用。


哨兵会记录这个消息 , 当拥有认为主观下线的哨兵到达 sentinel monitor 所配置的数量的时候 , 就会发起一次新的投票 , 然后切换主机,此时哨兵会重写 Redis 的哨兵配置文件 ,以适应新场景的需要。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
监控 NoSQL Redis
Redis Sentinel:秒杀系统背后的可靠性保障神器!
本文详细介绍了如何在个人项目中利用 Redis 哨兵模式保障系统的可靠性与高可用性。哨兵模式通过监控主从服务器状态、自动故障转移和通知客户端等功能,确保在主服务器宕机时系统仍能正常运行。适用于读请求多于写请求的场景,如秒杀系统,能有效缓解数据库压力。同时也探讨了哨兵模式在高并发场景下的优化方法及潜在缺陷,帮助开发者更好地应用该模式。
67 7
Redis Sentinel:秒杀系统背后的可靠性保障神器!
|
1月前
|
监控 NoSQL 算法
Redis Sentinel(哨兵)详解
Redis Sentinel(哨兵)详解
|
1月前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
2月前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
|
1月前
|
消息中间件 存储 NoSQL
python 使用redis实现支持优先级的消息队列详细说明和代码
python 使用redis实现支持优先级的消息队列详细说明和代码
37 0
|
2月前
|
缓存 NoSQL PHP
使用PHP-redis实现键空间通知监听key失效事件的技术与代码示例
通过上述方法,你可以有效地在PHP中使用Redis来监听键空间通知,特别是针对键失效事件。这可以帮助你更好地管理缓存策略,及时响应键的变化。
92 3
|
3月前
|
运维 监控 NoSQL
【Redis】哨兵(Sentinel)原理与实战全解~炒鸡简单啊
Redis 的哨兵模式(Sentinel)是一种用于实现高可用性的机制。它通过监控主节点和从节点,并在主节点故障时自动进行切换,确保集群持续提供服务。哨兵模式包括主节点、从节点和哨兵实例,具备监控、通知、自动故障转移等功能,能显著提高系统的稳定性和可靠性。本文详细介绍了哨兵模式的组成、功能、工作机制以及其优势和局限性,并提供了单实例的安装和配置步骤,包括系统优化、安装、配置、启停管理和性能监控等。此外,还介绍了如何配置主从复制和哨兵,确保在故障时能够自动切换并恢复服务。
|
6天前
|
SQL 存储 Linux
从配置源到数据库初始化一步步教你在CentOS 7.9上安装SQL Server 2019
【11月更文挑战第8天】本文介绍了在 CentOS 7.9 上安装 SQL Server 2019 的详细步骤,包括系统准备、配置安装源、安装 SQL Server 软件包、运行安装程序、初始化数据库以及配置远程连接。通过这些步骤,您可以顺利地在 CentOS 系统上部署和使用 SQL Server 2019。
|
7天前
|
SQL 存储 Linux
从配置源到数据库初始化一步步教你在CentOS 7.9上安装SQL Server 2019
【11月更文挑战第7天】本文介绍了在 CentOS 7.9 上安装 SQL Server 2019 的详细步骤,包括系统要求检查与准备、配置安装源、安装 SQL Server 2019、配置 SQL Server 以及数据库初始化(可选)。通过这些步骤,你可以成功安装并初步配置 SQL Server 2019,进行简单的数据库操作。
|
30天前
|
Linux 网络安全 数据安全/隐私保护
Linux系统之Centos7安装cockpit图形管理界面
【10月更文挑战第12天】Linux系统之Centos7安装cockpit图形管理界面
67 1
Linux系统之Centos7安装cockpit图形管理界面