Redis 系列笔记:

第一篇:Redis 基础命令
第二篇:Redis 常见应用场景
第三篇:Redis Cluster集群搭建
第四篇:Redis 主从及哨兵搭建
第五篇:Redis 主从及集群
第六篇:Redis 持久化
第七篇:Redis 分布式锁
第八篇:Redis 底层数据存储结构
第九篇:Redis 面试常问问题



前言

【个人笔记-Redis主从及集群】本篇博客只能算是简单总结,更详细的自行百度


一、Redis主从复制

1. 为什么需要主从复制

通过Redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。在一部分节点下线或者无法与集群的大多数节点进行通讯的情况下, 仍然可以正常运作。

2. 配置

只需要在Slave服务器上配置即可,Master不需要配置。

2.1. 配置主从注意事项

1、Redis Slave 也需要开启RDB持久化
2、配置与Master同样的连接密码 #因为后期Slave会有提升为Master的可能,Slave端切换Master同步后会丢失之前的所有数据
3、配置主从前,Redis只有配置文件以及命令执行文件,删除其他所有文件
4、Slave服务器一般为read-only

2.2. 配置主从

参考:Redis主从及哨兵搭建

2.3. 主从复制过程

主从复制主要有三种复制方式:全量复制、增量复制(持续复制、部分复制)。

2.3.1 全量复制

用于主从节点第一次复制的场景,后续有新增或更新就采用增量更新。

(1)从节点发送 psync 命令进行请求数据同步。
(2)主节点响应从节点。
(3)从节点收到主节点响应的 runIdoffset,将其保存到从节点本地。
(4)主节点在后台执行 bgsave 命令保存 RDB 文件到主节点的本地。
(5)主节点将第四步生成的 RDB 文件发送给从节点,子节点收到 RDB 文件后,保存到本地。
(6)主节点发送(5)步骤期间缓存的客户端命令
(7)从节点在(5)步骤保存完 RDB 文件后,就会把自身的旧数据清空。
(8)从节点加载 RDB 文件;
(9)从节点执行 AOF 操作。

2.3.2 增量复制

增量复制有两种情况:持续复制部分复制
持续复制就是正常情况下向从节点发送命令。
部分复制是当主从之间的网络故障等原因造成持续复制中断了,当从节点再次连上主节点后,主节点就补发数据给从节点。

2.3.2.1 持续复制

当有客户端的写命令请求到主节点后,主节点会做两件事:命令传播和将写命令写入到复制积压缓冲区。

命令传播:将写命令持续发送给所有从服务器,保持主从数据一致。这个就可以理解为持续复制了。
 
复制积压缓冲区:其实就是一个有界队列,保存着最近传播的写命令,而队列里面的每个字节都有一个偏移量标识。

2.3.2.2 部分复制

Redis 主从的部分复制就是指当主从之间的网络故障等原因造成持续复制中断了,当从节点再次连上主节点后,主节点就补发数据给从节点,避免了全量复制的过高开销。补发数据的来源就是复制积压缓冲的数据。

(1)当主节点之间失联后,如果时间超过了 repl-timeout 时间,主节点就认为从节点发生故障了,中断连接。
(2)主节点其实一直都在把客户端写命令放入复制积压缓冲区,所以即使断连了,主节点还是会保留断连期间的命令,但因为队列是固定的,当写命令太多时,就会导致部分命令被覆盖了。
(3)主从节点恢复连接。
(4)从节点发送 psync 命令给主节点,带有 runIdoffset 参数。runId 是上一次复制时保存的主节点的 runId值,offset 是从节点的复制偏移量。
(5)主节点接收到从节点的命令后,先判断传过来的 runId 是否和自己匹配,如果不匹配,则进行全量复制;如果 runId 匹配,则响应 CONTINUE,告诉从节点,可以进行部分复制了。我要把复制积压缓冲区的数据发给你了哦,请准备好接收。
(6)主节点根据子节点发送的偏移量,将复制积压缓冲区的数据发送给子节点。

2.4. 哨兵

2.4.1 哨兵搭建

参考:Redis主从及哨兵搭建

2.4.2 哨兵原理

Sentinel只是一个运行在特殊环境下的Redis,不提供数据存储服务。

2.4.2.1. Sentinel 与主从服务器建立连接

Sentinel 服务器启动之后便会创建于主服务器的 命令连接 ,并订阅主服务器的 _sentinel_:hello 频道以创建 订阅连接
Sentinel 默认会每 10 秒向主服务器发送 INFO 命令,主服务器则会返回主服务器本身的信息,以及其所有从服务器的信息。
根据返回的信息,Sentinel 服务器如果发现有新的从服务器上线后也会像连接主服务器时一样,向从服务器同时创建命令连接与订阅连接。
Sentinel 只会与主服务器和从服务器之间建立命令连接和订阅连接,而 Sentinel 之间只会建立命令连接,进行通信。

2.4.2.2. 判定主服务器是否下线

每一个 Sentinel 服务器每秒会向其连接的所有实例包括主服务器,从服务器,其他 Sentinel 服务器发送 PING 命令,根据是否回复 PONG 命令来判断实例是否下线。

  • 判定主观下线: 如果实例在收到 PING命令的 down-after-milliseconds 毫秒内(根据配置),未有有效回复。则该实例将会被发起 PING命令的 Sentinel 认定为主观下线。
  • 判定客观下线: 当一台主服务器被某个 Sentinel 服务器判定为客观下线时,为了确保该主服务器是真的下线, Sentinel 会向 Sentinel 集群中的其他的服务器确认,如果判定主服务器下线的 Sentinel 服务器达到一定数量时(一般是 N/2+1),那么该主服务器将会被判定为客观下线,需要进行故障转移。
2.4.2.3. 选举领头 Sentinel

当有主服务器被判定客观下线后,Sentinel 集群会选举出一个领头 Sentinel 服务器来对下线的主服务器进行故障转移操作。整个选举其实是基于 RAFT 算法而实现的,大致的思路如下:

  • 每个发现主服务器下线的 Sentinel 都会要求其他 Sentinel 将自己设置为局部领头 Sentinel
  • 接收到的 Sentinel 可以同意或者拒绝
  • 如果有一个 Sentinel 得到了半数以上 Sentinel 的支持则在此次选举中成为领头 Sentinel
  • 如果给定时间内没有选举出领头 Sentinel,那么会再一段时间后重新开始选举,直到选举出领头 Sentinel。
2.4.2.4. 选举新的主服务器

领头服务器会从从服务中挑选出一个最合适的作为新的主服务器。挑选的规则是:

  • 选择健康状态的从节点,排除掉断线的,最近没有回复过 INFO命令的从服务器。
  • 选择优先级配置高的从服务器
  • 选择复制偏移量大的服务器(表示数据最全)
  • 挑选出新的主服务器后,领头服务器将会向新主服务器发送 SLAVEOF no one命令将他真正升级为主服务器,并且修改其他从服务器的复制目标,将旧的主服务器设为从服务器,以此来达到故障转移。

参考:Redis 三种集群模式,你还傻傻分不清吗?


二、Redis集群

1. Cluster集群搭建

参考另一篇博客:Redis Cluster集群搭建

2. 集群原理

Redis 的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的内容。

Redis Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。

  • slots(槽位)计算
    hash_slot = CRC16(key) mod 16384 # 对 key 进行CRC16算法处理然后再对16384取余获取到slots(槽位)
  • 当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这 样当客户端要查找某个 key 时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不 一致的情况,还需要纠正机制来实现槽位信息的校验调整。

3. 节点间的内部通信机制

集群元数据的维护有两种方式:集中式、Gossip 协议。浅析redis cluster介绍与gossip协议
Redis Cluster 节点间采用 Gossip 协议进行通信。

Gossip 协议: 所有节点都持有一份元数据,不同的节点如果出现了元数据的变更,就不断将元数据发送给其它的节点,让其它节点也进行元数据的变更。

  • 优点:元数据的更新比较分散,不是集中在一个地方,降低了压力;
  • 缺点:元数据的更新有延时,可能导致集群中的一些操作会有一些滞后。
     

Gossip协议包含多种消息,包括pingpongmeetfail,等等。

  • meet: 某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信
    • redis-cli --cluster add-node 其实内部就是发送了一个gossip meet消息,给新加入的节点,通知那个节点去加入我们的集群。
  • ping: 每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据。【】
  • pong: 返回pingmeet,包含自己的状态和其他信息,也可以用于信息广播和更新。
  • fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。
     

pingpongmeet交换的信息有故障信息,节点的增加和移除,hash slot信息,等等
10000端口: 每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信的就是17001端口。
 

每个节点每隔一段时间都会往另外几个节点发送ping消息,同时其他节点接收到ping之后返回pong。

继续深入剖析ping消息
ping很频繁,而且要携带一些元数据,所以可能会加重网络负担。

  • 每个节点每秒会执行10次ping,每次会选择5个最久没有通信的其他节点。
  • 当然如果发现某个节点通信延时达到了cluster_node_timeout / 2,那么立即发送ping,避免数据交换延时过长,落后的时间太长了。
  • 比如说,两个节点之间都10分钟没有交换数据了,那么整个集群处于严重的元数据不一致的情况,就会有问题。
  • cluster_node_timeout可以调节,如果调节比较大,那么会降低发送的频率。
  • 每次ping,一个是带上自己节点的信息,还有就是带上1/10其他节点的信息,发送出去,进行数据交换。
  • 至少包含3个其他节点的信息,最多包含 总节点-2 个其他节点的信息。

4. Cluster集群选举原理

Slave发现自己的Master变为FAIL状态时,便尝试进行Failover,以期成为新的Master。由于挂掉的Master 可能会有多个Slave,从而存在多个Slave竞争成为Master节点的过程:

  • slave发现自己的master变为FAIL
  • 将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST 信息
  • 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个 epoch只发送一次ack
  • 尝试failoverslave收集master返回的FAILOVER_AUTH_ACK
  • slave收到超过半数masterack后变成新Master
  • slave广播Pong消息通知其他集群节点

注意:从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待 FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票。
延迟计算公式DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方 式下,持有最新数据的slave将会首先发起选举。(理论上)


三、Redis 主从、哨兵、Cluster集优缺点

3.1 主从复制

优点

  • 主节点负责写操作,从节点负责读操作;如果写少读多场景,配置多个从节点的话,效率非常高。
  • 数据热备份,提供多个副本。从节点宕机,影响较小。
     

缺点

  • 因为只有主节点能进行写操作,一旦主节点宕机,整个服务就无法使用。只能在从节点进行读操作。
  • Master的写的压力难以降低。
  • 主节点存储能力受到单机限制,存储数据量受限。
  • 同步风暴:因为数据都是从主节点同步到从节点的,如果有多个从节点的话,主节点的压力会很大,要合理分布从节点。

3.2 哨兵

优点

  • 对节点进行监控,来完成自动的故障发现与转移
     

缺点

  • 在主从切换的瞬间存在访问瞬断的情况,等待时间比较长,至少十来秒不可用。
  • 哨兵模式只有一个主节点对外提供服务,没法支持很高的并发
  • 单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。
  • 与主从相比,哨兵仅解决了手动切换主从节点问题,至于其他的问题,基本上仍然存在。

哨兵的主要问题还是由于中心架构,仅存在一个master节点引起的,写的效率太低。

3.3 Cluster集群

优点

  • 无中心架构:即有多个master节点,不像哨兵模式下仅有一个。这样写的压力就可以分散了;并且存储量也可以扩展了,因为多个主节点都可以存储一部分数据,总量要远大于单主节点架构。
  • 数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
  • 可扩展性:可线性扩展到 1000 多个节点,节点可动态添加或删除。(1000以上就不适合用Cluster集群了,节点之间的通信就会给集群带来压力)
  • 高可用性:部分节点不可用时,集群仍可用。通过增加 Slave 做 standby(备用数据) 数据副本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave 到 Master 的角色提升。
  • 降低运维成本,提高系统的扩展性和可用性。
     

缺点

  • Client实现复杂,驱动要求实现Smart Client,缓存slots mapping信息并及时更新,提高了开发难度,客户端的不成熟影响业务的稳定性。目前仅JedisCluster相对成熟,异常处理部分还不完善,比如常见的“max redirect exception”。
  • 节点会因为某些原因发生阻塞(阻塞时间大于clutser-node-timeout),被判断下线,这种failover是没有必要的。
  • 数据通过异步复制,不保证数据的强一致性。
  • 多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容易出现相互影响的情况。
  • Slave在集群中充当“冷备”,不能缓解读压力,当然可以通过SDK的合理设计来提高Slave资源的利用率。
  • Key批量操作限制,如使用mset、mget目前只支持具有相同slot值的Key执行批量操作。对于映射为不同slot值的Key由于Keys不支持跨slot查询,所以执行mset、mget、sunion等操作支持不友好。
  • Key事务操作支持有限,只支持多key在同一节点上的事务操作,当多个Key分布于不同的节点上时无法使用事务功能。
  • Key作为数据分区的最小粒度,不能将一个很大的键值对象如hash、list等映射到不同的节点。
  • 不支持多数据库空间,单机下的redis可以支持到16个数据库,集群模式下只能使用1个数据库空间,即db 0。
  • 复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
  • 避免产生hot-key,导致主库节点成为系统的短板。
  • 避免产生big-key,导致网卡撑爆、慢查询等。
  • 重试时间应该大于cluster-node-time时间。
  • Redis Cluster不建议使用pipeline和multi-keys操作,减少max redirect产生的场景。

参考:Redis学习之4种模式实践及机制解析(单机、主从、哨兵、集群)

四、Redis主从哨兵和集群的区别

(1)架构不同
  redis主从:一主多从;
  redis集群:多主多从;
 

(2)存储不同
  redis主从:主节点和从节点都是存储所有数据;
  redis集群:数据的存储是通过hash计算16384的槽位,算出要将数据存储的节点,然后进行存储
 
(3)选举不同
  redis主从:通过启动redis自带的哨兵(sentinel)集群进行选举,也可以是一个哨兵
  redis集群:集群可以自己进行选举
  
(4)节点扩容不同
  redis主从:只能扩容从节点,无法对主节点进行扩容;
  redis集群:可以扩容整个主从节点,但是扩容后需要进行槽位的分片,否则无法进行数据写入。

总结

Redis Cluster主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用Redis Cluster,数据量不是很大时,使用Sentinel就够了。Redis Cluster的性能和高可用性均优于哨兵模式。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐