前面两篇已经对Redis的基本数据类型,Redis的过期和持久化策略进行了讲述,但即便拥有了恢复的能力,而在故障恢复的这段时间服务也是完全挂掉不可用,对于一个高可用的系统来说,这是完全不能接受的,因此我们要告别单兵作战时代,看看Redis是如何进行集群作战的
Redis主从关系是通过slaveof命令来实现的,调用slaveof命令的服务器为从服务器,命令的参数是主服务器。从服务器通过复制来从主服务器获取数据,复制包含两个过程:同步(sync)和命令传播两个操作:
同步:将从服务器的数据状态更新为主服务器当前所处的状态
命令传播:当主服务器数据被修改时,将修改的命令应用到从服务器
同步分为完全同步和部分同步,完全同步通过sync命令完成,部分同步通过psync来实现
sync
(1)从服务器向主服务器发送sync命令
(2)主服务器执行bgsave命令,生成rdb文件,并使用一个缓冲区开始记录这一期间执行的写命令
(3)主服务将rdb文件发给从服务器,从服务器对数据进行载入
(4)主服务器将期间的命令发给重服务器,从服务器执行这些命令
后面就开始进入命令传播阶段
psync
从服务器有两种情况,一种是新服务器上线初始复制和断线重连,对于初次上线sync可以很好的工作,但是对于断线重连,可能大部分数据都是相同,此时在用RDB文件进行重建效率比较低。而psync命令具有完成重同步和部分重同步的功能。
完全重同步的过程和sync一样,部分重同步需要以下三个部分的信息:主服务器和从服务器的复制偏移量,主服务器的复制积压缓冲区、服务器运行ID(run ID)。
复制积压缓冲区是一个FIFO的队列,默认大小为1MB,用于保存最近的命令,当从服务器断线重连之后,可以比较自己的偏移量在缓存区中还有没有,如果没有需要完全重同步,如果从服务器保存的主服务器的run Id和当前主服务器不一致,也需要完全重同步(说明主服务器已经变了)
主从复制虽然完成了主从服务器之间的最终一致性,但没有自动故障转移和恢复的能力
Sentinel(哨兵)是Redis高可用的解决方案,由一个或多个Sentinel实例组成Sentinel系统来监控集群的状态,并自动完成故障转移、选主和恢复的能力。
Sentinel是一种特殊的Redis实例,其上不存储数据,只存储节点状态信息,并与其它Sentinel节点进行通信和数据交换。
Sentinel会与每个主/从服务器建立命令连接和订阅连接。会每10s通过命令连接向主/从服务器发送info命令,来从主服务器获取主服务器和其从服务器的状态,也会从从服务器获取其主服务器的状态信息。
Sentinel会以每2秒依次对从服务器hello频道发送命令信息,监控统一服务器的其它Sentinel因为也订阅了这个服务器的hello频道,所以也会收到该消息(基于这样订阅关系,来更新对监控服务器的认知),同时Sentinel也会对消息来源没有建立的Sentinel建立命令连接,这样所有监控统一服务器的Sentinel之间也能够相互通信了。
主观下线
当一个Sentinel与监控主服务器实例不可达时,就会将该master标记为主观下线
客观下线
向其他Sentinel询问,当从其他Sentinel收到足够数量的下线信息后,会判定服务器为客观下线,并开始故障转移操作
(1)发送命令询问其他Sentinel是否同意下线
(2)其他Sentinel响应
(3)统计下线响应数量,并标记客观下线
选举领头Sentinel
按照先到先得,最新得到半数票的Sentinel单选
故障转移
领头Sentinel对已下线的主服务器开启故障转移
(1)从从服务器选出一个作为主服务器(挑出的服务器执行slave no one)
(2)让已下线的主服务器的所有其他从服务器从属于该服务器
(3)已下线主服务器从属于该服务器
Redis集群是Redis提供的分布式数据库方案,集群通过分片的方式来进行数据共享,并提供复制和故障转移功能。
一个Redis集群由多个节点组成,Redis-Cluster是将数据按照槽来分别分给各个主节点,每个主节点负责一部分的槽,同时保存一份全局其它主节点负责的槽信息来实现请求转发,每个主节点可配置若干从节点来对数据进行复制和故障时选主,Redis集群整个数据库被分为16384(2的14次方)个槽。
重新分片
Redis集群的重分片由redis-trib实现,就是将待迁移的槽中的所有节点都迁移到新节点上的过程。在迁移过程中如果访问的节点被迁移了,会向客户端发送ack错误来指引到新节点进行访问, ACK错误是一次性的,下次对该槽的请求仍然会到原节点(因为可能槽中的其它数据还未迁移),而Move指令是永久的(客户端后续的请求都不会到原节点了)
故障检测
集群各节点之间通过ping,pong消息来相互传播服务器的状态。如果一个集群里面,有半数的节点都认为负责处理槽的主节点疑似下线,那么这个主节点将被标记为已下线
故障转移
(1)故障主节点有一个从节点被选中
(2)被选中节点执行slave no one,成为主节点
(3)将原主节点的指派改为自己
(4)广播pong消息,让其他节点知道该节点已经成为主节点
(5)新的主节点处理请求
选主操作
每个故障主节点的从节点向集群中的其它节点广播获取支持,得到半数以上票的从节点当选
几种消息
meet消息:邀请接受者加入当前集群
ping消息:集群每个节点默认每隔一秒从已知节点随机五个进行ping,判断是否在线
pong消息:对ping的回应。还可以通过pong来广播让其他节点刷新对该节点的认知(如选主过程新的主节点)
fail消息:当主节点判断另外一个节点进入fail状态时会广播节点的fail消息
publish消息:执行pushlish命令
其中meet、ping和pong是使用Gossip协议来实现的(通过流言蜚语的扩散传播)