Redis哨兵高可用架构搭建
每天多学一点点~
话不多说,这就开始吧…
文章目录
1.前言
之前搭建了redis的主从架构(一主两从),今天再优化一下,来学习下Redis的哨兵高可用架构。
Redis系列文章
2.Redis集群方案比较
-
主从模式
最初的redis架构模式,主写从读,为了防止服务器挂了(硬盘坏了)的情况下数据丢失,且不存在选举,若主服务器挂了,必须重写启动从服务器,改其配置让其成为主(当然可以写脚本,虽然现在基本上不怎么用了)。 -
哨兵模式
在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会 做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个主节点 内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率 -
高可用集群
redis集群是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性。Redis集群不需要 sentinel哨兵也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可 水平扩展,据官方文档称可以线性扩展到上万个节点(官方推荐不超过1000个节点)。redis集群的性能和高可用性均优于 之前版本的哨兵模式,且集群配置非常简单
3.Redis哨兵高可用架构搭建(一主二从三哨兵)
sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。 哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过 sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis 主节点通知给client端(这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)
- 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
- 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
之前已经搭建过了redis主从(1主2从),在次基础上搭建哨兵
Redis主从架构搭建以及主从复制原理
192.168.73.130:26380 192.168.73.130:26381 192.168.73.130:26382
建立三个文件夹 26380 26381 26382,将 sentinel.conf文件复制到其中对应的文件夹中,并改名 sentinel‐端口号.conf文件。
- 修改一下配置(对应到各个端口)
port 26380 # redis端口
daemonize yes #后台启动
protected-mode no #关闭自我保护
pidfile /var/run/redis‐sentinel‐26380.pid #redis进程文件id
logfile "26380.log" #redis日志文件
dir /usr/local/redis5.0.2/shaobin/data/26380 # redis日志文件目录
# sentinel monitor <master‐name> <ip> <redis‐port> <quorum>
# quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效,博主这里准备搭建三个哨兵,所以写2
sentinel monitor mymaster 192.168.73.130 6380 2 #指定redis主从的主节点(之前搭建的主节点ip)
# 每个Sentinel节点都要定期PING命令来判断Redis数据节点和其余Sentinel节点是否可达,如果超过指定时间(默认30000ms)且没有回复,则判定不可达
sentinel down-after-milliseconds mymaster 1500
# 当Sentinel节点集合对主节点故障判定达成一致时,Sentinel领导者节点会做故障转移操作,选出新的主节点,原来的从节点会向新的主节点发起复制操作,限制每次向新的主节点发起复制操作的从节点个数为1
sentinel parallel-syncs mymaster 1
- 启动sentinel哨兵实例(以sentinel.conf配置文件启动)
src/redis-sentinel /usr/local/redis5.0.2/shaobin/26380/sentinel-26380.conf
src/redis-sentinel /usr/local/redis5.0.2/shaobin/26381/sentinel-26381.conf
src/redis-sentinel /usr/local/redis5.0.2/shaobin/26382/sentinel-26382.conf
- 查看sentinel的info信息
redis-cli -p 26739
info sentinel # 查看sentinel的info信息
sentinel get-master-addr-by-name mymaster # 查看当前master
sentinel slaves mymaster # 查看监控的slaves节点
观察最后一行,可以看出,该sentinel节点监控的包括一个master节点(名为mymaster,该名字是之前在sentinel-*中定义的别名)和2个slave节点(slaves=2);而最后的sentinels=2则代表一共启动了3个sentinel节点对master slave节点进行监控。
4.Springboot整合redis哨兵
之前sringboot整合redis时候,大多数西奥伙伴可能选用的是jedis连接池,但在这里博主选springboot自带的用lettuce连接池。
- Jedis
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接 - Lettuce
Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
lettuce主要利用netty实现与redis的同步和异步通信。
- pom依赖
<!--spring boot redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--lettuce pool 缓存连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
- yml配置
spring:
application:
name: redistest
redis:
database: 0
timeout: 3000 #超时时间
lettuce: # 这里标明使用lettuce配置
pool:
max‐idle: 50 # 连接池中的最大空闲连接
min‐idle: 10 # 连接池中的最小空闲连接
max‐active: 100 # 连接池最大连接数(使用负值表示没有限制)
max‐wait: 1000 # 连接池最大阻塞等待时间(使用负值表示没有限制)
sentinel:
master: mymaster #主服务器所在集群名称
nodes: 192.168.73.130:26380,192.168.73.130:26381,192.168.73.130:26382
- redis序列化配置
/**
* redis序列化配置
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
- redis代码测试
/**
* redis 哨兵模式 测试
*/
@RestController
public class RedisTestController {
private static Logger logger = LoggerFactory.getLogger(RedisTestController.class);
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 测试节点挂了哨兵重新选举新的master节点,客户端是否能动态感知到
* 新的master选举出来后,哨兵会把消息发布出去,客户端实际上是实现了一个消息监听机制,
* 当哨兵把新master的消息发布出去,客户端会立马感知到新master的信息,从而动态切换访问的masterip
*/
@GetMapping("test_sentinel")
public void testSentinel() throws InterruptedException {
while (true) {
int i = 1;
redisTemplate.opsForValue().set("zjq" + i, i);
System.out.println("设置key:" + "zjq" + i);
i++;
Thread.sleep(1000);
}
}
}
运行上述代码,访问接口
现在将sentinel()
5.测试哨兵选举
现在将6380(主)节点kill掉,观察哨兵集群的变化
代码开始报错,连接不上6380,等过了一会,哨兵集群选举成功之后,又继续开始运行代码了。我们在看下现在的主节点是谁。
6382变成了主节点。
再把6380启动,主节点依然是6382,且数据已经同步~
dbsize # 查看db里面key的个数
6.哨兵选举流程
当一个master服务器被某sentinel视为客观下线状态后,该sentinel会与其他sentinel协商选出sentinel的leader进行故障转移工作。每个发现master服务器进入客观下线的sentinel都可以要求其他sentinel选自己为sentinel的leader,选举是先到先得。同时每个sentinel每次选举都会自增配置纪元(选举周期),每个纪元中只会选择一个sentinel的leader。如果所有超过一半的sentinel选举某sentinel作为leader。之后该sentinel进行故障转移操作,从存活的slave中选举出新的master,这个选举过程跟集群的master选举很类似。 哨兵集群只有一个哨兵节点,redis的主从也能正常运行以及选举master,如果master挂了,那唯一的那个哨兵节点就是哨兵leader了,可以正常选举新master。 不过为了高可用一般都推荐至少部署三个哨兵节点。为什么推荐奇数个哨兵节点原理跟集群奇数个master节点类似。
7.结语
世上无难事,只怕有心人,每天积累一点点,fighting!!!