redis哨兵模式

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,端口26380和26381,注意上述配置文件里的对应数字都要修改
复制代码
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主节点,同时会修改所有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节点作为从节点加入集群
 
哨兵的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", "zhuge"));
            System.out.println(jedis.get("sentinel"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
            if (jedis != null)
                jedis.close();
        }
    }
}
复制代码
哨兵的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项目核心配置:
复制代码
 1 server:
 2   port: 8080
 3 
 4 spring:
 5   redis:
 6     database: 0
 7     timeout: 3000
 8     sentinel:    #哨兵模式
 9       master: mymaster #主服务器所在集群名称
10      nodes: 192.168.0.60:26379,192.168.0.60:26380,192.168.0.60:26381
11    lettuce:
12       pool:
13         max-idle: 50
14         min-idle: 10
15         max-active: 100
16         max-wait: 1000
17     
复制代码
访问代码:
复制代码
 1 @RestController
 2 public class IndexController {
 3 
 4     private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
 5 
 6     @Autowired
 7     private StringRedisTemplate stringRedisTemplate;
 8 
 9     /**
10      * 测试节点挂了哨兵重新选举新的master节点,客户端是否能动态感知到
11      * 新的master选举出来后,哨兵会把消息发布出去,客户端实际上是实现了一个消息监听机制,
12      * 当哨兵把新master的消息发布出去,客户端会立马感知到新master的信息,从而动态切换访问的masterip
13      *
14      * @throws InterruptedException
15      */
16     @RequestMapping("/test_sentinel")
17     public void testSentinel() throws InterruptedException {
18         int i = 1;
19         while (true){
20             try {
21                 stringRedisTemplate.opsForValue().set("zhuge"+i, i+"");
22                 System.out.println("设置key:"+ "zhuge" + i);
23                 i++;
24                 Thread.sleep(1000);
25             }catch (Exception e){
26                 logger.error("错误:", e);
27             }
28         }
29     }
30 }
复制代码
StringRedisTemplate与RedisTemplate详解
spring 封装了 RedisTemplate 对象来进行对redis的各种操作,它支持所有的 redis 原生的 api。在RedisTemplate中提供了几个常用的接口方法的使用,分别是:
1 private ValueOperations<K, V> valueOps;
2 private HashOperations<K, V> hashOps;
3 private ListOperations<K, V> listOps;
4 private SetOperations<K, V> setOps;
5 private ZSetOperations<K, V> zSetOps;
RedisTemplate中定义了对5种数据结构操作
1 redisTemplate.opsForValue();//操作字符串
2 redisTemplate.opsForHash();//操作hash
3 redisTemplate.opsForList();//操作list
4 redisTemplate.opsForSet();//操作set
5 redisTemplate.opsForZSet();//操作有序set
StringRedisTemplate继承自RedisTemplate,也一样拥有上面这些操作。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
 
Redis客户端命令对应的RedisTemplate中的方法列表:
String类型结构
Redis
RedisTemplate rt
set key value
rt.opsForValue().set("key","value")
get key
rt.opsForValue().get("key")
del key
rt.delete("key")
strlen key
rt.opsForValue().size("key")
getset key value
rt.opsForValue().getAndSet("key","value")
getrange key start end
rt.opsForValue().get("key",start,end)
append key value
rt.opsForValue().append("key","value")
   
Hash结构
hmset key field1 value1 field2 value2...
rt.opsForHash().putAll("key",map) //map是一个集合对象
hset key field value
rt.opsForHash().put("key","field","value")
hexists key field
rt.opsForHash().hasKey("key","field")
hgetall key
rt.opsForHash().entries("key")  //返回Map对象
hvals key
rt.opsForHash().values("key") //返回List对象
hkeys key
rt.opsForHash().keys("key") //返回List对象
hmget key field1 field2...
rt.opsForHash().multiGet("key",keyList)
hsetnx key field value
rt.opsForHash().putIfAbsent("key","field","value"
hdel key field1 field2
rt.opsForHash().delete("key","field1","field2")
hget key field
rt.opsForHash().get("key","field")
 
 
List结构
lpush list node1 node2 node3...
rt.opsForList().leftPush("list","node") 
rt.opsForList().leftPushAll("list",list) //list是集合对象
rpush list node1 node2 node3...
rt.opsForList().rightPush("list","node") 
rt.opsForList().rightPushAll("list",list) //list是集合对象
lindex key index
rt.opsForList().index("list", index)
llen key
rt.opsForList().size("key")
lpop key
rt.opsForList().leftPop("key")
rpop key
rt.opsForList().rightPop("key")
lpushx list node
rt.opsForList().leftPushIfPresent("list","node")
rpushx list node
rt.opsForList().rightPushIfPresent("list","node")
lrange list start end
rt.opsForList().range("list",start,end)
lrem list count value
rt.opsForList().remove("list",count,"value")
lset key index value
rt.opsForList().set("list",index,"value")
   
Set结构
sadd key member1 member2...
rt.boundSetOps("key").add("member1","member2",...)
rt.opsForSet().add("key", set) //set是一个集合对象
scard key
rt.opsForSet().size("key")
sidff key1 key2
rt.opsForSet().difference("key1","key2") //返回一个集合对象
sinter key1 key2
rt.opsForSet().intersect("key1","key2")//同上
sunion key1 key2
rt.opsForSet().union("key1","key2")//同上
sdiffstore des key1 key2
rt.opsForSet().differenceAndStore("key1","key2","des")
sinter des key1 key2
rt.opsForSet().intersectAndStore("key1","key2","des")
sunionstore des key1 key2
rt.opsForSet().unionAndStore("key1","key2","des")
sismember key member
rt.opsForSet().isMember("key","member")
smembers key
rt.opsForSet().members("key")
spop key
rt.opsForSet().pop("key")
srandmember key count
rt.opsForSet().randomMember("key",count)
srem key member1 member2...
rt.opsForSet().remove("key","member1","member2",...)
posted @   lem985  阅读(204)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示