0%

redis主从复制哨兵和集群

1. 主从复制

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。

1.1 作用

主从复制的作用主要包括:

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  • 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
  • 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

1.2 全量复制

注意:在2.8版本之前只有全量复制,而2.8版本后有全量和增量复制:

image-20230831114442450

第一阶段是主从库间建立连接、协商同步的过程

  • 从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。
  • 主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库。

第二阶段,主库将所有数据同步给从库

  • 主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库。从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。

第三个阶段,主库会把第二阶段执行过程中新收到的写命令,再发送给从库

  • 当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了。

配置

1
2
3
4
5
6
7
# 主redis配置, 无需特殊配置, 因为在 docker 内, 需要修改一下bind
vi $PWD/redis1/redis.conf
bind 127.0.0.1 改为 bind 0.0.0.0

# 修改从redis配置, 修改 redis.conf 文件
vi $PWD/redis2/redis.conf
slaveof 172.17.0.1 63791

1.3 增量复制

在 Redis 2.8 版本引入了增量复制。

image-20230831115201039

当断开的slave重新连接上master的时候,slave将会发送psync命令(包含复制的偏移量offset),请求partial resync。如果请求的offset不存在,那么执行全量的sync操作,相当于重新建立主从复制。

当主服务器进行命令传播的时候,maser不仅将所有的数据更新命令发送到所有slave的replication buffer,还会写入replication backlog。

repl backlog

一个主库只分配一个repl backlog, 是在增量复制阶段出现。

它是为了从库断开之后,如何找到主从差异数据而设计的环形缓冲区,因为是环形结构,会直接覆盖起始位置数据。如果从库断开时间太久,repl_backlog_buffer环形缓冲区被主库的写命令覆盖了,那么从库连上主库后只能乖乖地进行一次全量复制。

replication buffer

主库会给每个新连接的从库,分配一个replication buffer。

replication buffer对应于每个slave 。从库也是一个client,每个client连上Redis后,Redis都会分配一个client buffer,Redis先把数据写到这个buffer中,然后再把buffer中的数据发到client socket中再通过网络发送出去,这样就完成了数据交互。

2. 哨兵

Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入。哨兵的核心功能是主节点的自动故障转移。

因为Redis Sentinel实际上就是一个运行在特殊模式下的Redis服务器,所以用户也可以使用命令redis-server sentinel.conf –sentinel去启动一个Sentinel:这里的–sentinel参数用于指示Redis服务器进入Sentinel模式,从而变成一个Redis Sentinel而不是普通的Redis服务器。

2.1 哨兵的功能

  • 监控(Monitoring)

    哨兵会不断地检查主节点和从节点是否运作正常。

  • 自动故障转移(Automatic failover)

    当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。

  • 配置提供者(Configuration provider)

    客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。

  • 通知(Notification)

    哨兵可以将故障转移的结果发送给客户端。

其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置提供者和通知功能,则需要在与客户端的交互中才能体现。

2.2 哨兵集群的组建

哨兵实例之间可以相互发现,要归功于 Redis 提供的 pub/sub 机制,也就是发布 / 订阅机制。

在主从集群中,主库上有一个名为__sentinel__:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的。在下图中,哨兵 1 把自己的 IP(172.16.19.3)和端口(26579)发布到__sentinel__:hello频道上,哨兵 2 和 3 订阅了该频道。那么此时,哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号。然后,哨兵 2、3 可以和哨兵 1 建立网络连接。

image-20230831124346791
1
2
3
# sentinel monitor <master-name> <master-host> <master-port> <quorum>
# 举例如下:
sentinel monitor mymaster 127.0.0.1 6379 2

2.3 哨兵监控Redis库

这是由哨兵向主库发送 INFO 命令来完成的。就像下图所示,哨兵 2 给主库发送 INFO 命令,主库接受到这个命令后,就会把从库列表返回给哨兵。接着,哨兵就可以根据从库列表中的连接信息,和每个从库建立连接,并在这个连接上持续地对从库进行监控。哨兵 1 和 3 可以通过相同的方法和从库建立连接。

image-20230831124508686

2.4 主库下线的判定

首先要理解两个概念:主观下线和客观下线。

  • 主观下线

    任何一个哨兵都是可以监控探测,并作出Redis节点下线的判断。

  • 客观下线

    有哨兵集群共同决定Redis节点是否下线。

当某个哨兵(如下图中的哨兵2)判断主库“主观下线”后,就会给其他哨兵发送 is-master-down-by-addr 命令。接着,其他哨兵会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票。

image-20230831124617329

如果赞成票数(这里是2)是大于等于哨兵配置文件中的 quorum 配置项(比如这里如果是quorum=2), 则可以判定主库客观下线了。

2.5 哨兵 Leader 的选举

为了避免哨兵的单点情况发生,所以需要一个哨兵的分布式集群。哨兵的选举机制其实很简单,就是一个Raft选举算法: 选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举。

任何一个想成为 Leader 的哨兵,要满足两个条件。第一,拿到半数以上的赞成票;第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。

以 3 个哨兵为例,假设此时的 quorum 设置为 2,那么,任何一个想成为 Leader 的哨兵只要拿到 2 张赞成票,就可以了。

2.6 哨兵Leader 故障转移

主从故障转移操作包含以下四个步骤:

  • 第一步:在已下线主节点(旧主节点)属下的所有「从节点」里面,挑选出一个从节点,并将其转换为主节点。
  • 第二步:让已下线主节点属下的所有「从节点」修改复制目标,修改为复制「新主节点」;
  • 第三步:将新主节点的 IP 地址和信息,通过「发布者/订阅者机制」通知给客户端;
  • 第四步:继续监视旧主节点,当这个旧主节点重新上线时,将它设置为新主节点的从节点;
新主库的选出
  • 过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点
  • 选择salve-priority从节点优先级最高(redis.conf)的
  • 选择复制偏移量最大,只复制最完整的从节点
image-20230831125253170
判定主库客观下线 和 是否能够主从切换?

Redis 1主4从,5个哨兵,哨兵配置quorum为2,如果3个哨兵故障,当主库宕机时,哨兵能否判断主库“客观下线”?能否自动切换?

1、哨兵集群可以判定主库“主观下线”。由于quorum=2,所以当一个哨兵判断主库“主观下线”后,询问另外一个哨兵后也会得到同样的结果,2个哨兵都判定“主观下线”,达到了quorum的值,因此,哨兵集群可以判定主库为“客观下线”。

2、但哨兵不能完成主从切换。哨兵标记主库“客观下线后”,在选举“哨兵领导者”时,一个哨兵必须拿到超过多数的选票(5/2+1=3票)。但目前只有2个哨兵活着,无论怎么投票,一个哨兵最多只能拿到2票,永远无法达到N/2+1选票的结果。

3. Redis Cluster集群

Redis-cluster是一种服务器Sharding技术,Redis3.0以后版本正式提供支持。Redis Cluster 功能 : 负载均衡,故障切换主从复制。

Redis Cluster要求至少需要3个master才能组成一个集群,同时每个master至少需要有一个slave节点。各个节点之间保持TCP通信。当master发生了宕机, Redis Cluster自动会将对应的slave节点提拔为master,来重新对外提供服务。

img

3.1 特点

  • 多主多从,去中心化

    从节点作为备用,复制主节点,不做读写操作,不提供服务。

  • 不支持处理多个key

    因为数据分散在多个节点,在数据量大高并发的情况下会影响性能;

  • 支持动态扩容节点

    这是我认为算是Rerdis Cluster最大的优点之一

  • 节点之间相互通信,相互选举,不再依赖sentinel

    准确来说是主节点之间相互“监督”,保证及时故障转移。

3.2 分片和重分片

与单机版Redis将整个数据库放在同一台服务器上的做法不同,Redis集群通过将数据库分散存储到多个节点上来平衡各个节点的负载压力。

具体来说,Redis集群会将整个数据库空间划分为16384个槽(slot)来实现数据分片(sharding),而集群中的各个主节点则会分别负责处理其中的一部分槽。当用户尝试将一个键存储到集群中时,客户端会先计算出键所属的槽,接着在记录集群节点槽分布的映射表中找出处理该槽的节点,最后再将键存储到相应的节点中。

qq163316

当用户想要向集群添加新节点时,只需要向Redis集群发送几条简单的命令,集群就会将相应的槽以及槽中存储的数据迁移至新节点。与此类似,当用户想要从集群中移除已存在的节点时,被移除的节点也会将自己负责处理的槽以及槽中数据转交给集群中的其他节点负责。

最重要的是,无论是向集群添加新节点还是从集群中移除已有节点,整个重分片(reshard)过程都可以在线进行,Redis集群无须因此而停机。

3.3 连接集群

为了连接集群,我们需要向客户端提供集群的节点地址。因为节点与节点之间一般都可以自动发现,所以我们通常只需要给定一个节点作为入口即可:

1
2
>>> nodes = [{"host":"127.0.0.1", "port":"30001"}]        
>>> cluster = RedisCluster(startup_nodes=nodes, decode_responses=True)

3.4 散列标签

在默认情况下,Redis将根据用户输入的整个键计算出该键所属的槽,然后将键存储到相应的槽中。但是在某些情况下,出于性能方面的考虑,或者为了在同一个节点上对多个相关联的键执行批量操作,我们也会想要将一些原本不属于同一个槽的键放到相同的槽里面。

为了满足这一需求,Redis为用户提供了散列标签(hash tag)功能,该功能会找出键中第一个被大括号{}包围并且非空的字符串子串(sub string),然后根据子串计算出该键所属的槽。这样一来,即使两个键原本不属于同一个槽,但只要它们拥有相同的被包围子串,那么程序计算出的散列值就是一样的,因此Redis集群就会把它们存储到同一个槽中。

1
2
3
4
5
127.0.0.1:30002> CLUSTER KEYSLOT {user}::10086
(integer) 5474

127.0.0.1:30002> CLUSTER KEYSLOT {user}::10087
(integer) 5474

4. 头脑风暴

  • 主从复制有全量复制和增量复制,全量就是rdb,增量就是一个环形缓冲区。

  • 哨兵是特殊的redis命令进行监控,哨兵要组成一个集群监控主库。选主哨兵leader然后主观和客观判断是否主从切换。

  • Redis cluster 集群是分区的方案,数据存在很多节点。每个节点又会有主从复制。

5. 参考资料

给作者打赏,可以加首页微信,咨询作者相关问题!