一、主从同步
单节点的Redis并发能力有上限,要进一步提升Redis的并发能力,就需要搭建主从集群,实现读写分离。
image.png
1.全量同步
主从第一次同步是全量同步:
image.png
- Replication id:简称replid,是数据集的标记,id一致说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
- offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave的数据落后于master,需要更新。
因此,slave做数据同步时,必须向master声明自己的Replication id和offset,master才可以判断到底需要同步哪些数据。
image.png
2.全量同步流程
- slave节点请求增量同步
- master节点判断replid,发现不一致,拒绝增量同步
- master将完整内存数据生成RDB,发送RDB到slave
- slave清空本地数据,加载master的RDB
- master将RDB期间的命令记录在repl_baklog,并持续将log中的命
令发送给slave - slave执行接收到的命令,保持与master之间的同步
3.增量同步
slave重启后同步,执行增量同步。
image.png
repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。
4.同步优化
- 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
- Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO。
- 适当提高repl baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
- 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
image.png
5.总结
全量同步和增量同步区别:
- 全量同步: master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl baklog,逐个发送给slave
- 增量同步: slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave
执行全量同步时机:
- slave节点第一次连接master节点时
- slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
执行增量同步时机:
slave节点断开又恢复,并且在repl_baklog中能找到offset时
二、Redis哨兵💂
1.哨兵的作用和原理
Redis提供了哨兵机制来实现主从集群的自动故障恢复。
image.png
作用:
- 监控: Sentinel 会不断检查master和slave是否按预期工作
- 自动故障恢复: 如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
- 通知: Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
2.服务状态监控
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
- 主观下线: 如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线.
- 客观下线:若超过指定数量 (quorum)的sentinel都认为该实例主观下线,则该实例客观下线。(quorum值最好超过Sentinel实例数量的一半)
image.png
3.选举master
一旦发现master故障,sentinal需要在slave中选择一个作为新的master,依据:
- 判断slave节点与master节点断开时间长短,如果超过指定值 (down-after-milliseconds* 10)则会排除该slave节点
- 判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
- 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
- 判断slave节点的运行id大小,越小优先级越高.
4.故障转移
image.png
当选择了其中一个slave为新的master后,故障转移步骤:
- sentinel给备选的slave1节点发送
slaveof no one命令,让该节点成为master - sentinel给所有其它slave发送
slaveof 192.168.150.101 7002命令,让这些slave成为新master的从节点,开始从新的master上同步数据 - sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
5.RedisTemplate的哨兵模式
在Sentinel集群监管下的Redis主从集群,其节点会因为自动故转移而发生变化,Redis的客户端必须感知这种变化及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。
1.在pom文件中引入redis的starter依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.在配置文件application.yml中指定sentinel相关信息:
spring:
redis:
sentinel:
master: mymaster # 指定master名称
nodes: # 指定redis-sentinel集群信意
- 192.168.150.101:27001
- 192.168.150.101:27002
- 192.168.150.101:27003
3.配置主从读写分离
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA PREFERRED);
}
ReadFrom配置redis的读取策略:
- MASTER:从主节点读
- MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
- REPLICA:从slave节点读取
- REPLICA_PREFERRED:优先从slave节点读取,所有slave节点不可用才读取master
三、Redis分片集群
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
- 海量数据存储问题
- 高并发写的问题
使用分片集群可以解决上述问题,分片集群特征:
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点
- master之间通过ping监测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点
image.png
1.散列插槽
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上
image.png
数据kev不是与节点绑定,而是与插槽绑定。
redis会根据key的有效部分计算插槽值,分两种情况:
- key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
- key中不包含“{}”,整个key都是有效部分
例如: key是num,那么就根据num计算,如果是{hcx}num,则根据hcx计算。计算方式是利用CRC16算法得到个hash值,然后对16384取余,得到的结果就是slot值。
2.集群伸缩
添加节点:redis -cli --cluster add-node ip:port ip:port
分配插槽:redis -cli --cluster reshard ip:port
3.故障转移
自动故障转移
- 实例与其他实例失去连接
- 疑似宕机
- 确定下线,自动升一个slave为master
手动故障转移
利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:
image.png
手动的Failover支持三种不同模式
- 缺省: 默认的流程,如图1~6步
- force: 省略了对offset的一致性校验
- takeover: 直接执行第5步,忽略数据一致性、忽略master状态和其它master的意见
4.RedisTemplate访问分片集群
RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致
1.引入redis的starter依赖
- 配置分片集群地址
3.配置读写分离
与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下:
spring:
redis:
cluster:
nodes: # 指定分片集群的每一个节点信息
- 192.168.150.101:7001192.168,150.101:7002
- 192.168.150.101:7003
- 192.168.150.101:8001
- 192.168.150.101:8002
- 192.168.150.101:8003











网友评论