不使用redis单节点,而是使用多个redis实例,分为主(master)和从(slave)节点分别做不同的事情,来提高整体业务的性能。就例如将读写进行分离,master节点主要负责写操作(可以读),而从节点只能进行读操作(不可以写)。这样可以提高读请求的响应速度,并且从节点可以设置多个,在高并发的情况下也可以很好地应对。
多个redis节点就会遇到一个问题,就是这些节点之间怎么进行数据同步,保证数据一致性?
全量同步: 主从第一次建立连接时或者backlog被覆盖导致offset过旧时会触发全量同步,一共分为三个阶段。
首先,每个 Master 都有一个唯一的复制 ID(replid
),Slave 在同步时会记录该 ID 和当前同步偏移量(offset
)。
当 Slave 连接 Master 时,会发送 PSYNC 命令。Master 判断能否进行增量同步,如果不能,就开始全量同步( 判断依据是slave保存的replid是否是master的replid ):
bgsave
生成 RDB 快照文件,并将其发送给 Slave;同步完成后,主从双方会维护相同的 replid
和 offset
,后续就可以进行 增量同步。
增量同步: 当主从节点已经完成一次全量同步并持续保持连接状态,或者从节点在短暂断线后重新连接成功时,将进入 增量同步阶段。此阶段不会再传输全量的 RDB 文件,而是通过命令流的形式将主节点新增的数据同步给从节点,性能更高、效率更好。
增量同步依赖两个核心机制:
replid
:用于标识主节点身份,确保当前连接的是之前同步的 Master;offset
:表示从节点已同步到的数据位置,用于计算需要增量同步的数据起点。当 Slave 断线重连时,会向 Master 发送 PSYNC
命令,并携带上次保存的 replid
和 offset
:
replid
是否和自身当前的一致;offset
是否还落在 Master 的 replication backlog buffer
(一个固定大小的内存环形缓冲区)中;offset
之后的写命令;若条件不满足(如
offset
太旧,尚未备份的数据被覆盖(因为backlog是一个环,进行的是 覆盖写 ,写满后会覆盖之前的数据)或replid
不一致),则无法进行增量同步,会回退为 全量同步。
slave节点宕机了可以直接重启然后找master进行数据同步就行,虽然有短暂的数据延迟,但是最终还是会与master数据一致。那么master节点宕机了怎么办呢?那么在master节点重启恢复的过程中,写操作就不会被执行了。
Sentinel作用: Redis就提供了哨兵(sentinel)机制来监测集群的健康状态;如果master故障了,那么sentinel就会选择一个slave提升为master。故障节点恢复后,依旧是以新提升的master作为master节点;并且是sentinel通知客户端哪个节点是master,哪个节点是slave的。
服务状态监控: 那么sentinel如何知道哪个节点还在线,哪个节点下线了呢?通过心跳检测机制。sentinel会每隔1s向集群所有实例发送ping命令,然后等待接收实例返回pong命令,如果超过一定时间没有返回,该sentinel就会认为该实例 主观下线 了。sentinel也有集群,如果超过指定数量(quorum)的sentinel都认为该实例下线了那么就认为该实例 客观下线 了,quorum值最好超过sentinel实例数量的一半。
选举新的master: 首先会根据slave节点和master节点断开的时间长短来排除一些数据过旧的节点,将超过指定值的slave节点排除;然后会判断slave节点的slave-priority值,值越小优先级越高;*接着判断slave节点的 offset值 ,越大说明数据越新,优先级越高;最后判断slave节点的运行id大小,越小优先级越高。
故障转移: 使用slaveof no one命令,让该节点成为master;然后会发送广播告诉其它所有的slave节点,让这些slave节点以新的master节点为master;然后sentinel会把故障的master节点标记为slave,等他重启之后,他就会变成新的master节点的slave节点。
哨兵和读写分离建立好了之后,客户端每次请求都是访问哨兵,哨兵会通知客户端哪个节点是master,哪些节点是slave,然后客户端就可以根据读请求还是写请求去访问对应的redis节点了。并且master宕机后,sentinel也能监测到并且自动地建立新的master并通知客户端。
数据量太大的时候,如果都放在一个redis中,高并发写的时候,所有并发请求访问一个master的话,性能依旧会有影响。并且高并发读的时候依旧会有问题。总之,分片集群就是用来解决 海量数据存储 以及 高并发请求 的。
特征: 集群中有多个master,每个master保存不同的数据。master都可以有多个slave节点。所以可以既满足分片集群,也满足主从集群。master和master之间可以通过ping来监测彼此健康状态,就不需要哨兵了,各个master之间可以进行健康检测。
散列插槽: Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,数据key不是与节点绑定,而是与插槽绑定,redis会根据key的有小部分计算插槽值,分为两种情况:
例如:key是num,那么就根据num计算,如果key是{itcast}num,那么就会根据{}中的itcast计算。计算方式是利用CRC16算法得到hash值,然后对16384取余,得到的结果就是slot值。
为什么key和slot绑定?而不是和redis节点绑定? 因为为了实现高效的水平扩展和动态迁移,Redis才引入了”slot“作为中间层,使得key和节点解耦,这样当增加redis节点或者删除redis节点的时候,只需要移动slot,将slot分配到不同的redis节点就可以了。
集群伸缩: 添加一个或者移除一个节点在集群中。 添加一个节点到redis集群中时,需要为这个集群分配插槽。
故障转移: 分片集群中没有哨兵,但是依旧是可以自动做故障转移的。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。