# 3.Redis哨兵

Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。

## 3.1.哨兵原理

### 3.1.1.集群结构和作用

哨兵的结构如图:

redis哨兵和集群区别_集群和哨兵_redis哨兵和集群的区别

哨兵的作用如下:

– **监控**:Sentinel 会不断检查您的master和slave是否按预期工作

– **自动故障恢复**:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主

– **通知**:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端

### 3.1.2.集群监控原理

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:

•主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例**主观下线**。

•客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例**客观下线**。quorum值最好超过Sentinel实例数量的一半。

redis哨兵和集群的区别_redis哨兵和集群区别_集群和哨兵

### 3.1.3.集群故障恢复原理

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:

– 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点

– 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举

– 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高

– 最后是判断slave节点的运行id大小,越小优先级越高。

当选出一个新的master后,该如何实现切换呢?

流程如下:

– sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master

– sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。

– 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点

### 3.1.4.小结

Sentinel的三个作用是什么?

– 监控

– 故障转移

– 通知

Sentinel如何判断一个redis实例是否健康?

– 每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线

– 如果大多数sentinel都认为实例主观下线,则判定服务下线

故障转移步骤有哪些?

– 首先选定一个slave作为新的master,执行slaveof no one

– 然后让所有节点都执行slaveof 新master

– 修改故障节点配置,添加slaveof 新master

## 3.3.RedisTemplate

在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。

### 3.3.2.引入依赖

在项目的pom文件中引入依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

### 3.3.3.配置Redis地址

然后在配置文件application.yml中指定redis的sentinel相关信息:

spring:
redis:
sentinel:
master: mymaster nodes:
- 192.168.150.101:27001
- 192.168.150.101:27002
- 192.168.150.101:27003

### 3.3.4.配置读写分离

在项目的启动类中,添加一个新的bean:

@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){ return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);}

这个bean中配置的就是读写策略,包括四种:

– MASTER:从主节点读取

– MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica

– REPLICA:从slave(replica)节点读取

– REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

# 4.Redis分片集群

## 4.1.搭建分片集群

主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:

– 海量数据存储问题

– 高并发写的问题

使用分片集群可以解决上述问题,如图:

redis哨兵和集群区别_集群和哨兵_redis哨兵和集群的区别

分片集群特征:

– 集群中有多个master,每个master保存不同数据

– 每个master都可以有多个slave节点

– master之间通过ping监测彼此健康状态

– 客户端请求可以访问集群任意节点,最终都会被转发到正确节点

## 4.2.散列插槽

### 4.2.1.插槽原理

Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:

redis哨兵和集群区别_redis哨兵和集群的区别_集群和哨兵

数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:

– key中包含”{}”,且“{}”中至少包含1个字符,“{}”中的部分是有效部分

– key中不包含“{}”,整个key都是有效部分

例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。

redis哨兵和集群的区别_redis哨兵和集群区别_集群和哨兵

如图,在7001这个节点执行set a 1时,对a做hash运算,对16384取余,得到的结果是15495,因此要存储到103节点。到了7003后,执行`get num`时,对num做hash运算,对16384取余,得到的结果是2765,因此需要切换到7001节点

### 4.2.1.小结

Redis如何判断某个key应该在哪个实例?

– 将16384个插槽分配到不同的实例

– 根据key的有效部分计算哈希值,对16384取余

– 余数作为插槽,寻找插槽所在实例即可

如何将同一类数据固定的保存在同一个Redis实例?

– 这一类数据使用相同的有效部分,例如key都以{typeId}为前缀

## 4.3.集群伸缩

redis-cli –cluster提供了很多操作集群的命令,可以通过下面方式查看:

集群和哨兵_redis哨兵和集群的区别_redis哨兵和集群区别

比如,添加节点的命令:

集群和哨兵_redis哨兵和集群的区别_redis哨兵和集群区别

### 4.3.1.需求分析

需求:向集群中添加一个新的master节点,并向其中存储 num = 10

– 启动一个新的redis实例,端口为7004

– 添加7004到之前的集群,并作为一个master节点

– 给7004节点分配插槽,使得num这个key可以存储到7004实例

这里需要两个新的功能:

– 添加一个节点到集群中

– 将部分插槽分配到新插槽

### 4.3.2.创建新的redis实例

创建一个文件夹:mkdir 7004
拷贝配置文件:cp redis.conf /7004
修改配置文件:sed /s/6379/7004/g 7004/redis.conf
启动redis-server 7004/redis.conf

### 4.3.3.添加新节点到redis

添加节点的语法如下:

集群和哨兵_redis哨兵和集群的区别_redis哨兵和集群区别

执行命令:redis-cli --cluster add-node  192.168.150.101:7004 192.168.150.101:7001

通过命令查看集群状态:redis-cli -p 7001 cluster nodes

如图,7004加入了集群,并且默认是一个master节点:

但是,可以看到7004节点的插槽数量为0,因此没有任何数据可以存储到7004上

### 4.3.4.转移插槽

我们要将num存储到7004节点,因此需要先看看num的插槽是多少:

redis哨兵和集群区别_redis哨兵和集群的区别_集群和哨兵

如上图所示,num的插槽为2765.

我们可以将0~3000的插槽从7001转移到7004,命令格式如下:

redis哨兵和集群区别_redis哨兵和集群的区别_集群和哨兵

具体命令如下:

建立连接:

集群和哨兵_redis哨兵和集群区别_redis哨兵和集群的区别

限时特惠:本站每日持续更新海量各大内部网赚创业教程,会员可以下载全站资源点击查看详情
站长微信:11082411

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。