Redis系列(一):Redis架构演进

Redis的架构是逐步演进的,从最初的单实例,到目前集群模式,我们可以看下整个演进过程,

主从复制

单个Redis实例的能力有限,在Redis的大多数使用场景下,都是读请求多于写请求,因此通过增加实例作为只读的从节点,不仅可以扩展Redis处理读请求的能力,还能做到数据冗余。
通过SLAVEOF,Redis可以指定一个实例为slave,同步另一个实例(master)的数据。同步过程如下,

SYNC

SYNC的过程
SYNC的过程,

  1. 当slave初次复制或者断线后重复制,向master发送SYNC命令
  2. master接到SYNC命令,执行BGSAVE,在后台生成一个RDB文件,同时把这段时间的写命令存储在缓冲区中
  3. BGSAVE执行完成,master把生成的RDB文件发送给slave。slave接收到RDB文件后进行载入
  4. master把缓冲区中的写命令发送给slave,salve执行写命令确保数据与master保存一致

注:在进行主从复制的过程中,不会影响master继续对外提供服务,因为BGSAVE并不会阻塞实例(和SAVE不同),这里可能会有疑问的是如果再生成RDB文件时,外部服务对master发送了写命令,是否会影响RDB文件的生成。答案是不会,Redis采用了COW来进行写时复制,感兴趣的可以详细了解下(有时间我也会单独写一篇文章介绍下COW)。

问题:

  • 每次复制都是全量复制,效率很低。主要是断线重连,slave可能只是确保一小部分数据,不得不全量复制。

PSYNC

为了解决SYNC的效率问题,Redis 2.8开始提供了PSYNC。

PSYNC1

PSYNC,从字面上也可以看出,支持部分复制(partial resynchronization)。它的实现思路通过offset和缓存一部分log来实现部分复制。

  • replication offset。master和slave分别会维护一个复制偏移量,如果master和slave的offset相等,意味着master与slave处于一致状态
  • replication backlog。master会维护一个固定长度、FIFO的复制积压缓冲区,用于保存写命令
  • run id。用于标识不同的redis实例
    采用PSYNC后主从复制的流程如下,
    PSYNC流程
  • 在slave第一次同步master、run id不同(master已经换了)或者落后master太多时,采用全量同步,和SYNC流程相同
  • slave发送的offset的数据仍然在master的复制缓冲区中,采用部分重同步,把偏移量后的所有数据同步给slave。

问题:

  • 更换master后,run id 不同,所有的slave都会执行全量同步

PSYNC2

Redis 4.0优化了PSYNC,优化了PSYNC1中的问题, 采用 Replication ID 和offset来实现部分同步。
master和slave都会维护一个复制缓存区,master和它所有的slave保持同一个Replication ID

高可用

主从复制解决了数据冗余的问题,但是在master挂掉后,切换master需要人工介入。为此,Redis 2.8推出了Sentinel,提供高可用的解决方案。
Sentinel可以监视多个master,在master进入下线状态时,自动把一个slave升级为master来继续对外提供服务。为了避免Sentinel的单点问题,Sentinel一般是集群部署。
每个Sentinel要监视哪些master实例初始是由Sentinel的配置文件决定的,

# sentinel monitor <master-name> <ip> <redis-port> <quorum>
# sentinel auth-pass <master-name> <password>
# sentinel down-after-milliseconds <master-name> <milliseconds>
# sentinel parallel-syncs <master-name> <numreplicas>

Sentinel在启动的时候,会根据配置文件来初始化要监视的master列表。每当Sentinel 接收到一个新的配置, 或者当Leader Sentinel 为主服务器创建一个新的配置时, 这个配置会与配置纪元一起被保存到磁盘里面。
Redis2.8.4开始提供增加、删除master的API。

# 添加要监控的master
SENTINEL MONITOR <name> <ip> <port> <quorum>
# 删除正在监控的master
SENTINEL REMOVE <name>

Sentinel与Redis实例之间的关系
Sentinel会保存它监视的所有master实例的信息,Sentinel与master实例会建立一个命令连接和一个订阅连接,用过命令连接,Sentinel定时向master发送INFO命令,来获取master的信息(包括master有哪些slave),然后通过订阅通道广播给其他的Sentinel实例。最终所有的Sentinel最终都可以互相知道哪些Sentinel监视哪些master。

服务监测

每个Sentinel默认会每秒向它连接的实例(包括master、slave、其他的Sentinel)发送PING命令,根据实例是否正常回复来判断实例是否在线。

# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached replica or sentinel
) should
# be unreachable (as in, not acceptable reply to PING, continuously, for
 the
# specified period) in order to consider it in S_DOWN state (Subjectivel
y
# Down).
#
# Default is 30 seconds.
sentinel down-after-milliseconds mymaster 30000

down-after-milliseconds 用来判断实例进入主观下线(S_DOWN)状态的时长。
当Sentinel认为master1处于主观下线状态,就会询问其他Sentinel,是不是也认为master1也处于主观下线状态。当超过一定数量的Sentinel也认为master1处于主观下线,那么master1就会被判定为客观下线(O_DOWN),然后开始执行故障转移。

故障转移

故障转移前,Sentinel会先选出一个leader来执行操作。
哨兵选举流程
参与选举的是所有监视master1的Sentinel实例,每次进行选举,不论是否成功,选举轮次(epoch)都会加一。在一次选举过程中,每个Sentinel都只会投给一个Sentinel,不会更改。一次选举的流程如下,

  • 所有的Sentinel都向其他Sentinel发送命令,希望对方投票给自己
  • Sentinel确定自己的选票是先到先得,先收到谁的请求,就把票投给谁
  • Sentinel在收到回复后,统计选票,如果某个Sentinel获得了半数以上Sentinel的投票,那么这个Sentinel就成为了leader。

切换Master

Leader Sentinel从被下线的master的所有slave实例中挑选一个,将其转为master,其余的slave改Follow新的master。如果后续旧master上线,Sentinel会把它转为新master的slave。
从候选的slave中挑选master,首先slave必须是仍然在线的、与Sentinel保持连接(最近5s正确回复Sentinel的INFO命令)、与master断开连接没有很久,然后把符合条件中的slave按照优先级(配置文件中的replica-priority)排序 -> 复制偏移量最大 -> run id最小。
在这里插入图片描述

RedisCluster

Sentinel只是高可用的解决方案,并不能提供扩展能力(写能力、存储能力)。Redis在3.0后开始提供对集群的支持。
// todo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值