引言

Redis,作为一种开源的、基于内存的数据结构存储系统,被广泛应用于各种场景,包括缓存、消息队列、短期存储等。

单一实例的工作模式通常无法保证Redis的可用性和拓展性,Redis提供了三种分布式方案:

  • 主从模式

  • 哨兵模式

  • 集群模式

1. Redis主从模式

1.1 什么是主从模式?

主从模式,是redis集群最基本的模式,主库负责读写,从库负责读。主库的数据会同步到从库,但是从库写的数据不会自动同步到主库,除非用写脚本等方式手动同步。这种模式应急能力比较差,假如出现宕机的情况,需要手动进行修改

1.2 全量同步
  1. master服务端收到slave的同步命令psync后,判断slave传过来的master_replid是否和mastermaster_replid一致,如果不一致或者传的是一个空的,就需要进行全量同步

  2. master开始执行bgsave命令,生成一个RDB文件,生成成功后,给到slave,并且将master_replidofferset传过去

  3. slave收到RDB文件后,清空slave自己内存中的数据,然后通过RDB文件重新加载数据

补充细节:

  • Redis4.0之前的版本,slavemaster传的不是master_replid,而是runid,但是runid每次实例重启都会改变,也就是会进行一次全量同步,所以Redis4.0版本后采用replid

  • master进行bgsave生成RDB文件时,因为bgsave命令是异步的,所以在同步时候,可能会接收其它指令,所以这些指令会先暂存在一个内存空间replication_buffer,等到slave加载完RDB文件后,再同步给slave

  • 设置replication_buffer大小可以通过如下进行配置

# 256mb:硬性限制,大于256M断开连接;64mb 60:软限制,超过64M并且超过了60s还没进行同步就会断开连接
client-output-buffer-limit replica 256mb 64mb 60

  • 内存空间replication_buffer不能设置太小,如果设置太小,超过了大小之后,为了数据安全,会关闭master跟从库的连接,再次连接就得重新全量同步,但是问题还在,可能导致无限同步问题

 1.3 增量同步

有全量同步就会有增量同步的,那么redis什么时候会进行增量同步?增量同步的流程是怎么样的?

在全量同步时候说过,master会给slave一个偏移量offerset,如果出现slavemaster网络断开一小会等情况,导致偏移量跟master差了一点,网络恢复,slave重新跟master连接后,这时slave会发送指令,判断是否需要增量同步还是全量同步?

  1. master会判断slave传过来的master_replid是否一致,如果一致,满足条件,进行下一步校验

  2. 增量同步会根据偏移量offerset和积压缓存数据来判断,增量同步会去积压缓存replication_backlog_buffer获取数据,如果偏移量只差了3条数据,同时在积压缓存里查找得到,就会进行增量同步

补充细节:

  • master_replid一致的情况,可能也不会进行增量同步,因为积压缓存的数据,可能是被覆盖了,导致需要增量同步的数据,查找不到,为什么会被覆盖?因为积压缓存是可以设置大小的,如果内存满了,就会覆盖之前的数据

  • 设置积压缓存replication_backlog_buffer的大小

repl-backlog-size 1mb

1.4 主从模式的工作原理 

在主从模式下,主节点负责处理所有的写操作,并将写操作记录在内存中的缓冲区。从节点从主节点获取这些写操作记录,并在自己的数据库上执行这些操作,从而保持与主节点的数据一致。此外,读请求可以在主节点和从节点上进行,从而实现读写分离,提高系统的读取性能。

具体的同步步骤如下:

  1. 从服务器连接到主服务器:首先,从服务器需要连接到主服务器。这通常通过在从服务器上执行SLAVEOF命令并指定主服务器的IP地址和端口号来完成。

  2. 发送SYNC命令:从服务器连接到主服务器后,它会发送一个SYNC命令。这个命令是Redis复制的核心,它会触发主服务器开始复制过程。

  3. 主服务器开始保存数据:收到SYNC命令后,主服务器会开始在后台保存其数据快照。同时,主服务器还会记录从接收到SYNC命令开始执行的所有写命令,这些命令将在数据快照完成后发送给从服务器。

  4. 主服务器发送数据快照:数据快照完成后,主服务器会将其发送给从服务器。从服务器在接收到数据快照后,会删除所有旧数据,然后使用接收到的数据快照来加载新数据。

  5. 主服务器发送缓存的写命令:数据快照发送完成后,主服务器会将在数据快照过程中记录的所有写命令发送给从服务器。从服务器在接收到这些命令后,会按照接收的顺序执行这些命令,以确保其数据与主服务器的数据保持一致。

  6. 主从同步完成,进入命令转发阶段:完成上述步骤后,主从服务器的数据就同步了。之后,主服务器每执行一次写命令,就会将这个命令发送给所有的从服务器。从服务器在接收到写命令后,会执行这个命令,以确保其数据始终与主服务器的数据保持一致。

2. Redis哨兵模式

 2.1 什么是哨兵模式?

Redis的主从模式是可以解决负载、数据备份等问题,但是,如果master宕机的情况,slave是不会自动升级为master的,必须手动升级,所以就有了哨兵集群的方案,以及后面介绍的cluster集群

先看看官网对Sentinel的介绍

大概意思是Redis Sentinel在不适用Cluster集群的时候,为Redis提供了高可用性,并且提供了检测、通知、自动故障转移、配置提供等功能

监控 :能够监控我的redis实例是否正常运行

通知:如果redis的实例出现问题,能够通知给其它实例以及其它Sentinel

自动故障转移:master宕机,slave可以自动升级为master

配置提供:Sentinel可以提供Redis的master实例地址,那么客户端只需要跟Sentinel进行连接,master宕机了会提供新的master

总而言之,Sentinel是独立于Redis服务的单独服务,并且它们之间是相互通信的,可以画图表示一下Redis的哨兵模式:

 2.2 哨兵模式的工作原理

在哨兵模式下,哨兵节点会定期检查主节点和从节点的运行状态。如果发现主节点发生故障,哨兵节点会在从节点中选举出一个新的主节点,并通知其他的从节点和哨兵节点。此外,哨兵节点还可以接收客户端的查询请求,返回当前的主节点信息,从而实现客户端的透明切换。

Sentinel主要负责三个方面的任务

  • 监控:通过发送命令,不间断的监控Redis服务器运行状态,包括主服务器和从服务器。

  • 提醒:当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

  • 自动故障迁移(核心任务)当哨兵监测到主服务器宕机,会自动在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器将其转换为主服务器(自动切换)。然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

 3. Reids 集群模式

3.1 什么是Redis Cluster模式?

redis的哨兵模式提供了比如监控、自动故障转移等高可用方案,但是这种方案,容量相对固定,要进行持续扩容或者数据分片就不适合,所以有另外一种更复杂的集群方案,Cluster集群模式。

Cluster集群模式,Cluster模式支持多主多从,这种模式,按照key进行虚拟槽位分配,使得key分配到不同的主节点,使用这种模式使得集群节点有更大的容量,也可以持续进行扩容,如果主库节点出现宕机,也会从从库节点选出一个新的主库节点

所以,如果redis的数据量不是很大,就可以使用哨兵模式,如果Redis存储的数据量比较大,而且需要持续扩容,那么就需要选择Cluster模式

3.2 Redis Cluster特点
  • 多个节点之间按照key进行虚拟槽分配,也就是我们说的数据分片

  • 当某些节点遇到故障的时候,其他节点还能继续服务

3.3 hash slot虚拟槽

那么如何进行数据分片?数据分片相当于数据库的分表,不同的数据放到不同的表里。数据分片就是要把不同的数据放到不同的实例里面。

所以,在Redis里面提出一个Hash槽,也可以称之为虚拟槽的概念。什么是虚拟槽?其实就是虚拟节点,Redis Cluster中有16384个虚拟槽。

key和虚拟槽怎么对应?会根据CRC16取模16383得到一个0到16383的值,计算公式是:slot = CRC16(key) & 16383,通过这个公式计算得到的值就表示key在哪个虚拟槽,举例:

set k1 1: 
CRC16(k1) & 16383 = 10

set k2 1:
CRC16(k1) & 16383 = 5468

set k3 1:
CRC16(k1) & 16383 = 10988

# 所以k1、k2、k3对应的槽位分别是10、5468、10988

如果有3台主库,对应的槽位分别为

master1 0-5460虚拟槽
master2 5461-10922虚拟槽
master3 10923-16383虚拟槽

则,k1、k2、k3分别会放在master1、master2、master3

3.4 集群模式的工作原理

 在集群模式下,Redis使用一种叫做哈希槽的技术来实现数据的分片。整个哈希空间被分成16384个哈希槽,每个节点负责一部分哈希槽。当一个键需要被存储时,Redis会根据键的值计算出一个哈希值,然后根据哈希值决定将这个键存储在哪个节点上。这样,读写请求就可以在多个节点上并行处理,提高了系统的性能。

在Redis集群模式下,任意一个Master节点都可以接受客户端的请求。当客户端向某个Master节点发送请求时,如果这个请求的键所对应的哈希槽不在这个Master节点负责的范围内,那么这个Master节点会返回一个重定向信息,告诉客户端应该向哪个节点发送请求。这个过程对客户端来说是透明的,客户端只需要按照重定向信息重新发送请求即可。这种方式确保了Redis集群可以有效地处理并分发客户端的请求,提高了系统的性能和可用性。 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐