Redis知识点整理(三)——多机数据库实现
本文紧接着上一篇的内容,简要讲述Redis多机数据库的实现原理,包括一主一从、哨兵模式和集群模式。
1、一主一从
1.1、旧版复制功能的实现
Redis 的复制功能分为同步(sync)和命令传播(command propagate)两个操作:
1、同步:
当客户端向从服务器发送 SLAVEOF 命令, 要求从服务器复制主服务器时, 从服务器首先需要执行同步操作, 也即是, 将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
从服务器对主服务器的同步操作需要通过向主服务器发送 SYNC 命令来完成, 以下是 SYNC 命令的执行步骤:
(1)从服务器向主服务器发送 SYNC 命令。
(2)收到 SYNC 命令的主服务器执行 BGSAVE 命令, 在后台生成一个 RDB 文件, 并使用一个缓冲区记录从现在开始执行的所有写命令。
(3)当主服务器的 BGSAVE 命令执行完毕时, 主服务器会将 BGSAVE 命令生成的 RDB 文件发送给从服务器, 从服务器接收并载入这个 RDB 文件, 将自己的数据库状态更新至主服务器执行 BGSAVE 命令时的数据库状态。
(4)主服务器将记录在缓冲区里面的所有写命令发送给从服务器, 从服务器执行这些写命令, 将自己的数据库状态更新至主服务器数据库当前所处的状态。
2.命令传播
在同步完成后,如果主服务器又执行了一条命令,主从数据库仍将不一致,为了让主从服务器再次回到一致状态, 主服务器需要对从服务器执行命令传播操作: 主服务器会将自己执行的写命令 —— 也即是造成主从服务器不一致的那条写命令 —— 发送给从服务器执行, 当从服务器执行了相同的写命令之后, 主从服务器将再次回到一致状态。
显然,在旧版复制功能中,即便对于断线后重复制的场景,即便断线前已经完成同步、正在进行命令传播,也需要从服务器再重新载入断线前的RDB文件中包含的所有键值对然后重新命令传播。这是相当低效的。
1.2、新版复制功能的实现
Redis从2.8版本开始支持使用PSYNC命令代替SYNC执行复制时的同步操作。支持完整重同步和部分重同步两种模式。
主服务器和从服务器分别维护一个复制偏移量,主服务器每次向从服务器传播N个字节就会将自己的复制偏移量加上N,从服务器每次收到主服务器传播来的N个字节也会将自己的复制偏移量加上N。
同时,主服务器也会在命令传播时将写命令与相应的复制偏移量入队到复制积压缓冲区,这是一个固定长度的FIFO队列。
在断线重连场景下,从服务器会通过PSYNC命令将自己的复制偏移量发送给主服务器,如果该偏移量之后的数据仍然存在于复制积压缓冲区中,则主服务器会进行部分重同步操作,否则执行完整重同步操作。
1.3、心跳检测
在命令传播阶段,从服务器会向主服务器发送命令,可用于检测主从服务器的网络连接状态、辅助实现min-slaves配置选项、检测命令丢失等功能。
2、哨兵模式
Sentinel 本质上只是一个运行在特殊模式下的 Redis 服务器,Sentinel 模式和普通 Redis 服务器能执行的命令不同。
哨兵模式中,由一个或多个Sentinel实例组成的Sentinel系统监视多个主服务器及从服务器。每个Sentinel以每秒一次的频率向实例发送PING命令;如果一台主服务器在一段时间内都向Sentinel返回无效回复,Sentinel就会将该主服务器标记为主观下线,为了确认这个主服务器是否真的下线,会再向监视该服务器的其他Sentinel进行询问,接收下线判断,如果有超过一定数量的Sentinel认为该主服务器已经下线,则该主服务器被判断为客观下线。
在一个主服务器被判定为客观下线时,监视这个服务器的各个Sentinel会协商选出一个领头Sentinel,进行故障转移操作,即将该主服务器下面的一个从服务器转换为主服务器,并让其他从服务器也复制该新的主服务器,旧的主服务器重新上线时会称为新的主服务器的从服务器。
3、集群模式
Redis 的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,此外在集群容量达到上限时在线扩容会变得很复杂。
所以,redis3.0加入了 Cluster 集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的内容。
一个Redis集群由多个节点组成,各个节点通过握手来将其他节点添加到自己所处的集群当中。
3.1、槽指派
Redis集群通过分片的方式保存数据库中的键值对,整个数据库被分为16384个槽,每个键都属于槽中的一个。这些槽可以分别指派给集群中的各个节点, 每个节点都会记录哪些槽指派给了自己并将消息发送给其他节点,因此最终每个节点都会知道数据库中的槽分别被指派给了哪些节点。
节点在接到一个命令请求时, 会先检查这个命令请求要处理的键所在的槽是否由自己负责, 如果不是的话, 节点将向客户端返回一个MOVED 错误, MOVED 错误携带的信息可以指引客户端转向至正在负责相关槽的节点。
3.2、重新分片
对 Redis 集群的重新分片工作是由客户端执行的, 重新分片的关键是将属于某个槽的所有键值对从一个节点转移至另一个节点。
如果节点 A 正在迁移槽 i 至节点 B , 那么当节点 A 没能在自己的数据库中找到命令指定的数据库键时, 节点 A 会向客户端返回一个 ASK 错误, 指引客户端到节点 B 继续查找指定的数据库键。
3.3、主从模式
为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。