博主以前写了一篇Redis哨兵搭建,并无对哨兵进行讲解,本篇填坑。html
同时,也为博主写Redis分布式锁(二)作一些前置知识。java
挖坑位置:Redis集群搭建(哨兵)node
在讲redis哨兵前,须要先简单讲解一下redis主从。web
俗话说,鸡蛋放在一个篮子里容易碎,那就把鸡蛋复制一份,放到其余篮子里。全部的高可用基本都是这个思路。redis
上一篇文章讲主从配置的时候,讲到一个配置属性slaveofspring
# 这个配置是redis-1中没有的,须要在redis-2中新增 # 这里的IP是redis-1的IP地址,端口是redis-1 6379.conf配置文件中port的值,默认值是6379 slaveof 1.1.1.1 6379
这个属性就是配置redis主从的。apache
这里分析如下上面这张图,能够发现如下几个特色json
这种redis架构解决了如下问题springboot
存在如下几个问题架构
基于以上的一些问题,咱们引出了redis哨兵
主从中存在一些问题是咱们不能接受的,好比,主库宕机=没法写入。咱们固然指望,宕机一个节点的时候,仍然能够对外服务,这才是高可用嘛~
假如不能自动切换主库,咱们该怎么作呢?运维童鞋,先无论主库了(已经宕机了),在从库中选择一个做为新的主库启动,优先提供服务嘛~至于主库,稍后再分析宕机缘由,解决问题。
本着软件能解决的问题,就不使用人力,咱们可不能够下一个软件,来代替运维童鞋的这些操做?
这个就是哨兵的功能雏形了。
哨兵监视主从redis,一旦redis主库宕机,哨兵切换主库,客户端再写入数据的时候,向新的主库中写入。在切换的时候,给运维童鞋一条通知,运维童鞋再处理。是否是很6?
从上面能够看出,咱们只有一个哨兵,若是这个哨兵宕机了,那咱们的保障就没有了。
咱们能够把哨兵也集群起来,优化结构以下:
你能够把哨兵理解为zookeeper或者是eureka,哨兵至关于一个注册中心(固然不单单是注册中心的功能),客户端也从哨兵读取redis主从库信息。三个哨兵组成了一个集群的注册中心,当有一个哨兵宕机,还有其余哨兵存活,依然能够服务。
这样哨兵Sentinel也集群起来了,redis也有主从,咱们这个时候能够说,提供了一套高可用的redis。
但这样的架构并非绝对完美的,仍然存在一些问题。
依旧不能解决主从中的一个问题“主库写入数据成功,还没来得及同步到从库,主库宕机”。
例如主库上写入了一把锁,还没来得及把锁的信息同步到从库,主库挂了,从库切换为了主库,然而这个新的主库上并无锁。引发了锁失效。
如何解决呢?
手动调整数据吧,少年。
若是是锁的场景,能够用zookeeper来代替redis分布式锁来解决。
博主使用的springboot来演示,使用工具包lettuce
<!-- data-redis中集成了lettuce --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- redis连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!-- alibaba json --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.72</version> </dependency>
server: port: 80 spring: redis: password: 密码 sentinel: # 这个配置在 哨兵配置文件中 master: 你的集群名称 # 26379 端口是哨兵的默认端口 nodes: 10.101.36.19:26379,10.101.36.20:26379,10.101.36.21:26379 lettuce: pool: # 最大连接数 max-active: 30 # 连接池中最大空闲连接数 max-idle: 15 # 最大阻塞等待连接时长 默认不限制 -1 max-wait: 2000 # 最小空闲连接数 min-idle: 10 # 连接超时时长 shutdown-timeout: 10000
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * redis 配置类 将RedisTemplate交给spring托管 */ @Configuration public class RedisConfig { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setValueSerializer(genericFastJsonRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("test") public class TestController { @Autowired private RedisTemplate redisTemplate; @GetMapping public String Test(){ redisTemplate.opsForValue().set("xujp", "sentinel"); String rst = (String) redisTemplate.opsForValue().get("xujp"); return rst; } }
postman直接get请求便可
在redis链接工具中查看
主库:
从库:
这个时候把主库手动关闭
查看哨兵日志
能够看到主节点已切换完成
26721:X 20 Jul 2020 15:08:40.941 # +switch-master mymaster 10.101.36.20 6379 10.101.36.19 6379
这时候,在postman中再次发送请求
请求成功。
有兴趣的童鞋能够再测试一下内容:
这里博主再挖一坑,redis哨兵模式切换主库的时候,如何通知运维人员呢?
本文挖坑: