Redis 主从复制是指:将一台 Redis 服务器的数据复制到其它的 Redis 服务器,前者所在的 Redis 服务器也被称为 “主节点”(Master / Leader),后者则被称为 “从节点”(Slave / Follower)。数据从主节点复制到从节点,主节点的主要任务是实现写入数据的任务(也有读数据的权限),而从节点则只负责读取数据。在 Redis 的默认配置中,每个启动的 Redis 服务都是主节点

主节点

一个主节点可以有多个从节点,但是对于每个从节点来讲,它都只能属于一个主节点。即主节点和从节点之间的对应关系为 \(1\) 对 \(N\) ,如下图所示:

主从复制的目的

由于单个的 Redis 服务可能会出现异常,使得 Redis 服务不可用,因此有必要对这种情况进行进一步的处理。

主从复制的目的就是为了解决单一的 Redis 可能会出现的问题,同时,通过主从复制实现 Redis 的读写分离,能够进一步提高整体 Redis 的性能。

主从复制只要提供了如下的功能:

  • 数据冗余:主从复制实现了数据的备份,实际上提供了数据冗余的实现方式
  • 故障恢复:当主节点出现异常时,可以将一个从节点选举成为一个新的主节点,从而提供了故障恢复的功能
  • 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器的负载。在写少读多的业务场景下,通过多个从节点分担读负载,可以极大地提高 Redis 服务能够承载的并发量
  • 高可用

环境搭建

具体可以参考官方文档:https://redis.io/topics/cluster-tutorial

或者 https://segmentfault.com/a/1190000038995016 也是一篇介绍比较全面的博客

集群搭建的步骤比较简单,在这里略过

主从复制的实现原理

Redis 的主从复制分为以下两个阶段:sync 阶段和 command propagate 阶段。

sync(同步)阶段

当从节点启动之后,会发送 sync 指令给主节点,要求全量同步数据,具体的步骤如下图所示:

  1. Slave 节点向 Master 节点发送 sync 指令,以请求数据同步
  2. Master 节点在接收到 sync 指令后,会执行一次 BGSAVE 指令,将当前 Master 节点中的数据保存到对应的 RDB 文件中。当 Master 节点完成 RDB 文件的导出后,再将导出的 RDB 文件发送给 Slave 节点。由于在这个过程中 Master 节点依旧有可能发生数据写入操作,在这种情况下 Master 节点会将执行的指令放入到对应的缓冲区
  3. Slave 节点在接受到 Master 节点导出的 RDB 文件之后,会删除现有节点的所有数据,然后加载这个 RDB 文件的内容到 Slave 节点
  4. Slave 节点数据加载完成之后,Master 会将缓冲区中暂存的指令发送到 Slave 节点
  5. Slave 执行收到的指令,完成数据的同步

Command Propagate 阶段

这个阶段也被称为 “命令传播” 阶段,数据同步完成之后,如果后续 Master 节点继续收到了新的写入操作的指令,那么也需要将该命令传播到 Slave 节点以完成数据的同步。这个过程就被称为 “命令传播”

psync 指令

上文提到 Slave 节点在启动时通过发送 sync 指令到 Master 节点用户获取数据的同步,在 Slave 节点启动的时候执行 sync 指令来进行同步是很合理的。但是如果在运行的过程中,由于网络抖动,使得 Slave 断开了同 Master 节点的连接,那么 Slave 节点再再次连接到 Master 节点时依旧通过 sync 指令来进行同步,那么性能就会非常差。

为了解决这个问题,自 Redis 2.8 开始,引入了 psync 指令来代替 sync 指令

psync 指令会根据不同的情况,来执行全量重同步和部分重同步

  • 全量重同步:当从节点是第一次与主节点建立连接的时候,那么就会执行全量重同步,这个同步过程和上文 sync + command propagate 进行同步的过程一致
  • 部分重同步:从 Slave 节点的复制偏移量在 Master 节点的复制积压区中寻找待同步的数据

psync 通过 Redis 的节点 ID 来判断 Slave 节点是否是第一次与 Master 节点进行同步

复制偏移量:Master 节点和 Slave 节点都保存着一份赋值偏移量,当 Master 节点每次向 Slave 节点发送 \(n\) 字节的数据时,就会在 Master 节点上将偏移量增加 \(n\);而每次 Slave 节点在接收到 \(n\) 字节的数据时,也会将节点上的偏移量增加 \(n\)。

在 “命令传播阶段”,Slave 节点会定期发送心跳 REPLYCONF ACK {offset} 指令,这里的 offset 就是 Slave 节点的偏移量。当 Master 节点在收到这个心跳指令之后,会对比自己的 offset 和收到的 offset,如果发现有数据丢失,那么 Master 节点就会推送丢失的那段数据给 Slave 节点。这个过程如下图所示:

复制积压缓冲区:由主节点维护的的一个固定长度(默认为 \(1\) MB)的队列,该队列存储了每个字节值与对应的复制偏移量。

由于复制积压缓冲区的大小是固定的,因此它保存的是最近 Master 节点执行的写操作命令。当 Slave 节点将 offset 发送给 Master 节点之后,Master 节点会根据 offset 与复制积压缓冲区的大小来决定是否可以使用部分重同步。如果 offset 后面的数据依旧存在于复制积压缓冲区,则执行部分重同步,否则执行全量重同步

节点 ID:Redis 实例启动之后,就会产生一个唯一的标识 ID,用于标识当前的 Redis 实例

Master 节点同 Slave 节点进行第一次连接同步时,Master 节点会将 ID 发送给 Slave 节点,Slave 节点在收到 Master 节点的 ID 之后会将他们进行保存。如果在 Slave 节点和 Master 节点之间的连接由于某些原因断开了,那么当 Slave 在恢复到与 Master 节点之间的链接时,Slave 节点会将这个 ID 发送给 Master 节点,Master 节点会将该 ID 与自己的实例 ID 进行比较,如果相同,则说明该 Slave 之前同 Master 节点是连接的。

Redis 哨兵

上面的集群搭建之后,如果 Master 节点崩溃了,在上面的情况下不会将 Slave 节点转换为 Master 节点,因此 Master 节点崩溃之后整个 Redis 集群就不能再执行写入操作。

为了解决这个问题,提高系统的可用性,Redis 提供了 Sentinel(哨兵)来实现 Slave 节点到 Master 节点的转换

“哨兵” 节点本质上也是一个 Redis 节点,但是和 Master 节点和 Slave 节点不同,“哨兵” 节点只是监视 Master 节点和 Slave 节点,并不执行相关的业务操作。具体关系如下图所示:

“哨兵” 的主要有以下几个作用:

  • 监控 Redis 节点运行状态
  • 通知:当被监控的 Redis 节点出现问题时,Sentinel 可以通过向 API 或者管理员以及其它应用发送通知
  • 自动故障转移:当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移,它会在失效的 Redis 集群中寻找一个有效的节点,并将它升级为新的 Master 节点,并将原来失效的 Master 节点降级为 Slave 节点。当客户端试图访问已经失效的 Master 节点时,Redis 集群也会想客户端返回新的 Master 节点的地址,使得 Redis 集群可以使用新的 Master 节点代替失效的 Master 节点

由于使用单个的 “哨兵” 来监视 Redis 集群的节点也不是完全可靠的,因为 “哨兵” 节点也有可能会出现故障,因此,一般情况下会使用多个 “哨兵” 节点来监视整个 Redis 集群,如下图所示:

由于存在多个 哨兵 节点,因此在 Redis Sentinel 中,对于 Redis 节点的下线也有区分:

  • 主观下线(Subjectively Down,即 SDOWN):指单个 Sentinel 节点对集群中的节点作出下线判断
  • 客观下线(Objectively Down,即 ODOWN):指多个 Sentinel 节点对集群中的节点作出 “SDOWN” 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,作出 Redis 节点下线的判断

一个 Sentinel 节点可以通过向另一个 Sentinel 节点发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的节点已经下线

Redis Sentinel 部署

具体可以参考:https://www.cnblogs.com/youzhibing/p/8466491.html#autoid-4-0-0,这个部署比较简单,在此略过

值得注意的是有关 sentinel 的配置文件:


# sentinel的端口号,如果配置3个Sentinel,只需要修改这个port即可,即:26380、26381、26382
port 26381 # 设置当前 sentinel 是否放入后台运行
daemonize yes # 设置当前 sentinel 的日志输出文件
logfile "/tmp/sentinel/sentinel-26381.log" # 该 sentinel 对应的进程对应的文件描述符
pidfile "/var/run/redis-sentinel-26381.pid" # 监视127.0.0.1:6701、6700、6702 的节点,且至少有2个Sentinel判断主节点失效,才可以自动故障迁移
sentinel monitor myslave-2 127.0.0.1 6702 2
sentinel monitor mymaster 127.0.0.1 6700 2
sentinel monitor myslave-1 127.0.0.1 6701 2 # 那么Sentinel将这个服务器标记为主观下线(subjectively down,简称 SDOWN )
sentinel down-after-milliseconds mymaster 60000

具体的配置文件的相关属性可以参考官方文档:https://redis.io/topics/sentinel

实现原理

对于节点的检测,主要通过以下三种方式来进行检测:

  • 每个 Sentinel 会每隔 \(10\)s 向主节点中发送 INFO 指令,通过该指令可以获得整个 Redis 节点的拓扑图。在这个时候,如果有新的节点加入或者有节点退出当前的集群,那么 Sentinel 就能够感知到拓扑图结构的变化。
  • 每个 Sentinel 节点每隔 \(2\)s 会向指定的 Channel 发布自己对 Master 节点是否正常的判断以及当前 Sentinel 节点的信息,通过订阅这个 Channel,可以获得其它 Sentinel 节点的信息以及对 Master 节点的存活状态的判断
  • 每个 Sentinel 节点每隔 \(1\)s 就会向所有节点(包括 Sentinel 节点、Master 节点以及 Slave 节点)发送 PING 指令来检测节点的存活状态

主节点的选举流程:

  • 当一个 Sentinel 节点判断 Master 节点不可用时,首先进行 “SDOWN”(主观下线),此时,这个 Sentinel 通过 SENTINEL is-masterdown-by-addr 指令获取其它哨兵节点对于当前 Master 节点的判断情况,如果当前哨兵节点对于当前 Master 节点的下线判断数量超过了在配置文件中定义的票数,那么该 Master 节点就被判定为 “ODOWN”(主观下线)
  • Sentinel 节点列表中也会存在一个 Leader Sentinel,该 Sentinel 会从原主节点的从节点中选出一个新的主节点,具体步骤如下所示:
    • 首先,过滤掉所有的 ODOWN 节点
    • 选择 slave-priority 最大的节点,如果存在则选择这个节点为新的主节点,如果没有则继续下面的流程
    • 选出复制偏移量最大的节点,如果有则返回;如果没有则继续执行下面的流程
    • 选择 run_id (服务运行 id) 最小的节点
  • 当选择出新的主节点之后,Leader Sentinel 节点会通过 SLAVEOF NO ONE 命令让选择出来的节点成为主节点,然后通过 SLAVEOF 命令让其他节点成为该节点的从节点

参考:

[1] https://mp.weixin.qq.com/s/bs5NfSkQlFbFp7KMQ9aLmw

[2] https://redis.io/topics/sentinel

Redis 的主从复制的更多相关文章

  1. redis的主从复制配置

    redis的主从复制配置 一.     原理 Redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架 ...

  2. Redis总结(三)Redis 的主从复制

    接着上一篇,前面两篇我总结了<Redis总结(一)Redis安装>和<Redis总结(二)C#中如何使用redis> 所以这一篇,会讲讲Redis 的主从复制以及C#中如何调用 ...

  3. 实现Redis的主从复制配置

    实现Redis的主从复制配置比较简单,而且容易明白. 下图是要配置的主从复制结构图: 1.说明 Redis主从复制中一个主服务可以有多个从服务,一个从服务可以有多个从服务. 配置比较简单,只需要更改r ...

  4. redis的主从复制部署和使用

    reids一种key-value的缓存数据库目前非常流行的被使用在很多场景,比如在数据库读写遇到瓶颈时缓存且读写分离会大大提升这块的性能,下面我就说说redis的主从复制 首先需要启动多个redis实 ...

  5. redis实现主从复制-单机测试

    一.redis实现主从复制-单机测试1.安装redis tar -zxvf redis-2.8.4.tar.gzcd redis-2.8.4make && make install2. ...

  6. 8. redis的主从复制和sentinal

    一. redis主从复制(读写分离) redis的主从复制分为两类节点:1个master和多个slave,master进行读写操作,slav进行只读操作 启动步骤: 主节点照常启动,slave节点启动 ...

  7. Redis基础学习(五)—Redis的主从复制

    一.概述     Redis的主从复制策略是通过其持久化的rdb文件来实现的,其过程是先dump出rdb文件,将rdb文件全量传输给slave,然后再将dump后的操作实时同步到slave中.让从服务 ...

  8. Redis配置主从复制

    Redis配置主从复制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.操作环境介绍 1>.操作系统环境 [root@node101.yinzhengjie.org.cn ...

  9. Redis的主从复制(十一)

    1>什么是主从复制 持久化保证了即使redis服务重启也不会丢失数据,因为redis服务重启后(在使用aof和rdb方式时,如果redis重启,则数据从aof文件加载)会将硬盘上持久化的数据恢复 ...

  10. 基于配置文件的redis的主从复制

    redis中主从复制有很多种配置方法: 1. 使用配置文件即为redis.conf来配置 在随从redis中配置 # slaveof {masterHost} {MastePort} slaveof ...

随机推荐

  1. .NET反编译神器ILSpy怎么用?

    前言 上一篇文章我们介绍了4款免费且实用的.NET反编译工具,这篇文章主要来说说ILSpy这个工具该如何安装和使用. ILSpy ILSpy是一款免费.开源的 .NET 反编译工具,能够将已编译的 . ...

  2. oracle-查看oracle当前连接数,会话数

    查看当前系统允许的进程连接数:方法一: show parameter process; 查看processes一列 方法二: select name,value from v$parameter wh ...

  3. webgl centroid质心插值的一点理解

    质心插值说的是什么 2023.10.04再次review这个细节点: https://www.opengl.org/pipeline/article/vol003_6/ https://github. ...

  4. Blackmail

    Blackmail Arthur Hailey The chief house officer, Ogilvie, who had declared he would appear at the Cr ...

  5. Rust学习 | Rustlings通关记录与题解

    2023年6月19日决定对rust做一个重新的梳理,整理今年4月份做完的rustlings,根据自己的理解来写一份题解,记录在此. 周折很久,因为中途经历了推免的各种麻烦事,以及选择数据库作为未来研究 ...

  6. ELK日志企业案例:(5.3版本)

    1.shell三剑客同居.分析nginx日志: 1)在企业生产环境中,日志内容主要用来做什么? 日志内容主要用于运维人员.开发人员.DBA排错软件服务故障的,因为通过日志内容能够第一时间找到软件服务的 ...

  7. AtCoder Beginner Contest 321(ABC321)

    A. 321-like Checker 直接模拟. Code B. Cutoff 直接暴力枚举 \([0\sim100]\),每次把第 \(n\) 个数当作当前枚举的 \(i\),然后看看条件是否满足 ...

  8. 开发现代化的.NetCore控制台程序:(2)创建一个C#项目模板

    前言 上一篇文章(开发一个现代化的.NetCore控制台程序,包含依赖注入/配置/日志等要素)介绍了开发现代化的.NetCore控制台程序的细节,但这还不够,我又创建了一个脚手架模板,并命名为 Flu ...

  9. PZthon

    一道新式题目,python.exe的分析 这个时候没有思路不要紧,直接wp 先用特别的软件执行.exe程序,就是对.exe进行反编译 然后在反编译脚本的目录写就有了一个打包文件夹 在里面找到文件的.p ...

  10. go基础-方法

    概述 方法是面向对象编程 (OOP) 的一个特性,在 C++/Java 语言中方法是类函数,go做为函数式编程语言,通过特有技能支持相似的功能,所以说go也支持面向对象编程特性. go 方法本质也是函 ...