Redis中如何实现主从复制

52次阅读
没有评论

共计 3492 个字符,预计需要花费 9 分钟才能阅读完成。

Redis 中如何实现主从复制,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面丸趣 TV 小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

Redis 复制概论

数据库复制指的是发生在不同数据库实例之间,单向的信息传播的行为,通常由被复制方和复制方组成,被复制方和复制方之间建立网络连接,复制方式通常为被复制方主动将数据发送到复制方,复制方接收到数据存储在当前实例,最终目的是为了保证双方的数据一致、同步。

复制示意图

Redis 复制方式

Redis 的复制方式有两种,一种是主(master)- 从(slave)模式,一种是从(slave)- 从(slave)模式,因此 Redis 的复制拓扑图会丰富一些,可以像星型拓扑,也可以像个有向无环:

Redis 集群复制结构图

通过配置多个 Redis 实例独立运行、定向复制,形成 Redis 集群,master 负责写、slave 负责读。

复制优点

通过配置多个 Redis 实例,数据备份在不同的实例上,主库专注写请求,从库负责读请求,这样的好处主要体现在下面几个方面:

1、高可用性

在一个 Redis 集群中,如果 master 宕机,slave 可以介入并取代 master 的位置,因此对于整个 Redis 服务来说不至于提供不了服务,这样使得整个 Redis 服务足够安全。

2、高性能

在一个 Redis 集群中,master 负责写请求,slave 负责读请求,这么做一方面通过将读请求分散到其他机器从而大大减少了 master 服务器的压力,另一方面 slave 专注于提供读服务从而提高了响应和读取速度。

3、水平扩展性

通过增加 slave 机器可以横向(水平)扩展 Redis 服务的整个查询服务的能力。

复制缺点

复制提供了高可用性的解决方案,但同时引入了分布式计算的复杂度问题,认为有两个核心问题:

数据一致性问题,如何保证 master 服务器写入的数据能够及时同步到 slave 机器上。

编程复杂,如何在客户端提供读写分离的实现方案,通过客户端实现将读写请求分别路由到 master 和 slave 实例上。

上面两个问题,尤其是第一个问题是 Redis 服务实现一直在演变,致力于解决的一个问题。

复制实时性和数据一致性矛盾

Redis 提供了提高数据一致性的解决方案,本文后面会进行介绍,一致性程度的增加虽然使得我能够更信任数据,但是更好的一致性方案通常伴随着性能的损失,从而减少了吞吐量和服务能力。然而我们希望系统的性能达到最优,则必须要牺牲一致性的程度,因此 Redis 的复制实时性和数据一致性是存在矛盾的。

Redis 复制原理及特性 slave 指向 master

举个例子,我们有四台 redis 实例,M1,R1、R2、R3,其中 M1 为 master,R1、R2、R3 分别为三台 slave redis 实例。在 M1 启动如下:

./redis-server ../redis8000.conf --port 8000

下面分别为 R1、R2、R3 的启动命令:

 ./redis-server ../redis8001.conf --port 8001 --slaveof 127.0.0.1 8000 ./redis-server ../redis8002.conf --port 8002 --slaveof 127.0.0.1 8000 ./redis-server ../redis8003.conf --port 8003 --slaveof 127.0.0.1 8000

这样,我们就成功的启动了四台 Redis 实例,master 实例的服务端口为 8000,R1、R2、R3 的服务端口分别为 8001、8002、8003,集群图如下:

Redis 集群复制拓扑

上面的命令在 slave 启动的时候就指定了 master 机器,我们也可以在 slave 运行的时候通过 slaveof 命令来指定 master 机器。

复制过程

Redis 复制主要由 SYNC 命令实现,复制过程如下图:

Redis 复制过程

上图为 Redis 复制工作过程:

slave 向 master 发送 sync 命令。

master 开启子进程来讲 dataset 写入 rdb 文件,同时将子进程完成之前接收到的写命令缓存起来。

子进程写完,父进程得知,开始将 RDB 文件发送给 slave。

master 发送完 RDB 文件,将缓存的命令也发给 slave。

master 增量的把写命令发给 slave。

值得注意的是,当 slave 跟 master 的连接断开时,slave 可以自动的重新连接 master,在 redis2.8 版本之前,每当 slave 进程挂掉重新连接 master 的时候都会开始新的一轮全量复制。如果 master 同时接收到多个 slave 的同步请求,则 master 只需要备份一次 RDB 文件。

增量复制

上面复制过程介绍的最后提到,slave 和 master 断开了、当 slave 和 master 重新连接上之后需要全量复制,这个策略是很不友好的,从 Redis2.8 开始,Redis 提供了增量复制的机制:

增量复制机制

master 除了备份 RDB 文件之外还会维护者一个环形队列,以及环形队列的写索引和 slave 同步的全局 offset,环形队列用于存储最新的操作数据,当 slave 和 maste 断开重连之后,会把 slave 维护的 offset,也就是上一次同步到哪里的这个值告诉 master,同时会告诉 master 上次和当前 slave 连接的 master 的 runid,满足下面两个条件,Redis 不会全量复制:

slave 传递的 run id 和 master 的 run id 一致。

master 在环形队列上可以找到对呀 offset 的值。

满足上面两个条件,Redis 就不会全量复制,这样的好处是大大的提高的性能,不做无效的功。

增量复制是由 psync 命令实现的,slave 可以通过 psync 命令来让 Redis 进行增量复制,当然最终是否能够增量复制取决于环形队列的大小和 slave 的断线时间长短和重连的这个 master 是否是之前的 master。

环形队列大小配置参数:

repl-backlog-size 1mb

Redis 同时也提供了当没有 slave 需要同步的时候,多久可以释放环形队列:

repl-backlog-ttl 3600

免持久化复制

免持久化机制官方叫做 Diskless Replication,前面基于 RDB 文件写磁盘的方式可以看出,Redis 必须要先将 RDB 文件写入磁盘,才进行网络传输,那么为什么不能直接通过网络把 RDB 文件传送给 slave 呢?免持久化复制就是做这个事情的,而且在 Redis2.8.18 版本开始支持,当然目前还是实验阶段。

值得注意的是,一旦基于 Diskless Replication 的复制传送开始,新的 slave 请求需要等待这次传输完毕才能够得到服务。

是否开启 Diskless Replication 的开关配置为:

repo-diskless-sync no

为了让后续的 slave 能够尽量赶上本次复制,Redis 提供了一个参数配置指定复制开始的时间延迟:

repl-diskless-sync-delay 5

slave 只读模式

自从 Redis2.6 版本开始,支持对 slave 的只读模式的配置,默认对 slave 的配置也是只读。只读模式的 slave 将会拒绝客户端的写请求,从而避免因为从 slave 写入而导致的数据不一致问题。

半同步复制

和 MySQL 复制策略有点类似,Redis 复制本身是异步的,但也提供了半同步的复制策略,半同步复制策略在 Redis 复制中的语义是这样的:

 允许用户给出这样的配置:在 maste 接受写操作的时候,只有当一定时间间隔内,至少有 N 台 slave 在线,否则写入无效。

上面功能的实现基于 Redis 下面特性:

Redis slaves 每秒钟会 ping 一次 master,告诉 master 当前 slave 复制到哪里了。

Redis master 会记住每个 slave 复制到哪里了。

我们可以通过下面配置来指定时间间隔和 N 这个值:

min-slaves-to-write  number of slaves min-slaves-max-lag  number of seconds

当配置了上面两个参数之后,一旦对于一个写操作没有满足上面的两个条件,则 master 会报错,并且将本次写操作视为无效。这有点像 CAP 理论中的“C”,即一致性实现,虽然半同步策略不能够完全保证 master 和 slave 的数据一致性,但是相对减少了不一致性的窗口期。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注丸趣 TV 行业资讯频道,感谢您对丸趣 TV 的支持。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-03发表,共计3492字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)