一、前言

  最近由于疫情影响,时间比较多,所以开始学习之前一直想学,但是却没时间学的Redis。这两天研究了一下Redis的持久化以及主从复制机制,现在已经很晚了,就不多废话了。这篇博客就来谈一谈Redis的主从复制机制。在这里需要提醒一下,主从复制依赖于Redis的快照持久化(RDB),所以如果不了解持久化,请先去研究那一块的内容,可以看看这篇博客:详细分析Redis的持久化操作—RDB与AOF

二、正文

2.1 什么是主从复制

  首先我们来谈一谈最基本的问题——什么是主从复制,为什么需要它?我们知道,现在的应用基本上都会使用集群进行部署,同一个应用部署在多台服务器上,各台服务器互相同步,各自承担一部分任务,以此来减轻单台服务器的压力。而主从复制就是Redis用来对存储相同数据的多台服务器进行同步的机制。

  假设我们只在一台服务器上部署了Redis服务器,那所有需要访问Redis服务器的请求,都需要这一台服务器来处理,这对服务器来说有很大的压力。如果访问的很频繁,那么一台服务器根本处理不过来,所以我们需要多台服务器同时部署Redis,然后每一台服务器承担一部分任务。

  如果我们部署了多台Redis服务器,存储相同的数据,为同一个应用进行服务,那么不难想到,我们需要处理一个问题——数据同步。我们必须保证这多台服务器的Redis数据库中,存储的数据是一致的,而且都应该是正确的数据,否则将会导致对请求进行错误的处理,比如查询出的是过期的数据,或者对已经过期的数据进行了修改。而主从复制,就是Redis对这多台服务器进行数据同步的机制。

  在主从复制机制中,Redis将服务器分为主服务器从服务器,主服务器负责接收用户提交的修改指令,修改数据库中的数据,同时将修改同步到从服务器中,而从服务器的任务就是与主服务器进行数据同步,并分担本应该由主服务器执行的查询请求,减小主服务器的压力,除此之外,为了减轻主服务器的压力,我们也可以关闭主服务器的持久化操作,而让从服务器来进行持久化。

2.2 主从复制的实现过程

  完整的主从复制包含以下两步:

  1. 同步:将从服务器当前的状态,更新为主服务器当前的状态,也就是使用主服务器中存储的数据,替换掉从服务器的数据;
  2. 命令传播:主服务器执行每一次修改操作后,都需要告知从服务器,让从服务器执行相同的操作,以保证一致性;

  下面我就来分别分析一下这两个过程的详细实现。

2.3 同步的实现原理

  从服务器与主服务器同步,需要使用到SYNC指令,详细的执行流程如下:

  1. 从服务器连接到主服务器,并向主服务器发送SYNC指令;
  2. 主服务器接收到SYNC指令后,开始执行BGSAVE指令(快照持久化),此时主服务器将调用fock(),创建一个子进程,子进程去生成Redis当前状态的一个快照;在这个过程中,新到达主服务器的写指令将会被记录在缓冲区;
  3. 主服务器执行完BGSAVE后,将快照文件发送给从服务器,在发送的过程中,如果还有新的写指令到达,也会继续记录在缓冲区;从服务器接收到主服务器发来的快照文件后,将丢弃自己内存中的数据,开始加载快照文件中记录的数据,加载完成后,就可以处理接收到的请求了;
  4. 主服务器在发送完快照文件后,开始将缓冲区中记录的写指令也同步到从服务器;从服务器接收到主服务器发来的指令,便依次执行这些指令,执行完后,就与主服务器的状态一致了;

2.4 命令传播的实现原理

  为什么需要命令传播?这个应该很好理解。经过上面的同步后,主服务器与从服务器存储的数据就一致了,这之后,从服务器就可以分担查询操作,但是写操作还是需要主服务器完成。所以,虽然当前主从服务器已经一致,但是主服务器如果执行了一次写操作,而从服务器没有执行,它们又将变成不一致的状态。而命令传播的实现原理很简单:主服务器每次执行写操作,都会将这个写指令发送给从服务器,从服务器接收到后,也执行这个写指令,这样就能让主服务器和从服务器持续的保持一致

  有人可能会想,为什么是将指令发送到从服务器,而不是重新执行一次同步操作呢?答案很简单,因为上面的同步操作,需要很大的开销。执行BGSAVE指令创建快照,需要创建一个子进程,同时生成一个文件,需要进行大量的磁盘IO,在数据量很大的情况下,可能会使主服务器产生数毫秒甚至是一秒的停顿。而向从服务器传输一个指令的开销,要比上面的同步小得多。

2.5 部分重同步介绍

  以上介绍的主从复制过程,是一个开销非常大,而且比较耗时的操作(主要是同步过程耗时),于是从Redis2.8开始,提供了一种优化机制——部分重同步。我们考虑这样一种情况,假设一台从服务器已经与主服务器完成了同步,进入了命令传播阶段,但是由于某些原因,主从服务器之间的网络连接断开了,从服务器在一段时间后,重新连接上了主服务器。按理来说,从服务器和主服务器断开连接的这段时间,没有同步对主服务器的写操作,此时它们已经不一致了,那么从服务器需要重新执行一次主从复制,这又是一次非常耗时的操作。而Redis2.8之后,提供了一种优化机制,若在上面的情况发生时,如果满足某些条件(具体条件之后叙述),可以不进行一次完整的主从复制,而是只同步断开连接的这段时间里,没有同步的操作,这就是部分重同步。

  Redis2.8之后,提供了一个新的指令来实现部分重同步,这个指令就是PSYNC。从2.8开始,实现主从复制使用的就不是SYNC了,而是PSYNC,它可以算是SYNC的升级版本。PSYNC支持两种模式:

  • 完整重同步:如果Redis判断当前从服务器需要与主服务器重新进行一次完整的主从复制,则PSYNC指令将执行与SYNC指令完全一样的操作,上面已经描述过了,这里就不重复叙述了;
  • 部分重同步:若从服务器与主服务器断线重连后,满足某些条件,则不进行完整重同步,而是只同步断线过程中,没有同步的部分;

2.6 部分重同步的实现原理

  下面我们就来详细分析一下,部分重同步是如何实现的。部分重同步需要依赖以下三个部分:

  • 服务器的运行id
  • 主服务器的复制积压缓冲区;
  • 主从服务器的复制偏移量;

(1)服务器的运行 id

  每一台服务器都会被分配一个运行id,用来标识服务器的身份。从服务器在与一台主服务器连接后,会记录主服务器的id。从服务器与主服务器断开后,可能会重新连接一台主服务器,但是并不一定就是原来的那一台。当从服务器连接到一台主服务器后,会向主服务器发送自己记录的主服务器id,主服务器判断这是不是自己,如果是,表明从服务器之前连接的就是自己,则有可能可以使用部分重同步机制,否则,将重新进行一次完整同步。

(2)主服务器的复制积压缓冲区

  首先,复制积压缓冲区是一个固定长度,先进先出的队列,默认 1MB。主服务器在接收到用户发来的写指令时,不仅仅会将写指令发送给从服务器进行同步,同时还会将这个指令放入到复制积压缓冲区中,目的是在从服务器没有成功接收到的时候能够重传。复制缓冲区的结构大致如下:

  可以看到,对于复制积压缓冲区中的每一个字节,都有一个对应的偏移量。如果当前缓冲区已经满了,但是又有新的指令需要放入其中,则会将最先放入其中的指令移除,腾出足够空间后,将新指令放入,也就是LRU算法(最近最久未使用),所以,缓冲区中能够存储的指令是有限的。

(3)主从服务器的复制偏移量

  主服务器和从服务器会分别维护自己的复制偏移量,主服务器每发送出一个字节,主服务器偏移量就+1,而从服务器每完成一个字节的同步,从服务器偏移量就+1

  什么情况下会触发部分重同步呢?答案就是:若从服务器与主服务器断开连接,并重新连接到同一个主服务器后,会将自己记录的复制偏移量发送给主服务器,主服务器判断这个偏移量之后的所有字节,是否还在复制缓冲区中,如果在,则表明可以进行部分重同步,将复制缓冲区中,这个偏移量之后的所有字节发送给从服务器;若不完全包含,则表明从服务器需要同步的数据,有一部分无法在缓冲区中找到,此时就需要进行一次完整同步。

2.7 配置从服务器

  下面讲一讲如何将一台Redis服务器,配置为从服务器,有两种方式:

(1)配置文件

  可以在配置Redis的配置文件中,加入以下配置项:

slaveof 主服务器ip 主服务器端口

  在配置文件中配置了上面这一行,则当前服务器就是一台从服务器,它启动时,就会尝试区连接上面上面这个配置项指定好的主服务器,并在连接成功后发送PSYNC指令,完成之前介绍的步骤。

(2)指令

  第二种方式就是使用指令,在Redis服务器输入下面这一行指令,当前服务器就会作为一个从服务器,尝试连接主服务器,并进行主从复制:

127.0.0.1:6379> SLAVEOF 主服务器ip 主服务器端口

2.8 主从复制的安全性

  在使用Redis 复制功能时的设置中,强烈建议在 主服务器 和 从服务器 中启用持久化。当不可能启用时,例如由于非常慢的磁盘性能而导致的延迟问题,应该配置实例来避免重置后自动重启

  为了更好地理解为什么关闭了持久化并配置了自动重启的 主服务器 是危险的,检查以下故障模式,这些故障模式中数据会从 主服务器 和所有 从服务器 中被删除:

  1. 我们设置节点 A 为 主服务器 并关闭它的持久化设置,节点 BC 从 节点 A 复制数据。
  2. 节点 A 崩溃,但是他有一些自动重启的系统可以重启进程。但是由于持久化被关闭了,节点重启后其数据集合为空。
  3. 节点 B 和 节点 C会从节点 A 复制数据,但是节点 A 的数据集是空的,因此复制的结果是它们会销毁自身之前的数据副本。

  当 Redis Sentinel 被用于高可用并且 主服务器 关闭持久化,这时如果允许自动重启进程也是很危险的。例如, 主服务器 可以重启的足够快以致于 Sentinel 没有探测到故障,因此上述的故障模式也会发生。任何时候数据安全性都是很重要的,所以如果 主服务器 使用复制功能的同时未配置持久化,那么自动重启进程这项应该被禁用

三、总结

  以上就对Redis的主从复制做了一个比较详细的描述,时间太晚了,就不说别的了,希望能够为需要的人答疑解惑吧。

四、参考

深入分析Redis的主从复制机制的更多相关文章

  1. Redis进阶:Redis的主从复制机制

    Redis进阶:Redis的主从复制机制 主从复制机制介绍 单机版的Redis存在性能瓶颈,Redis通过提高主从复制实现读写分离,提高了了Redis的可用性,另一方便也能实现数据在多个Redis直接 ...

  2. Redis主从复制机制详解

    Redis主从复制机制详解 Redis有两种不同的持久化方式,Redis服务器通过持久化,把Redis内存中持久化到硬盘当中,当Redis宕机时,我们重启Redis服务器时,可以由RDB文件或AOF文 ...

  3. Redis的主从复制与Redis Sentinel哨兵机制

    1    Redis的主从复制 1.1   什么是主从复制 持久化保证了即使redis服务重启也不会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损 ...

  4. Redis系列(四):Redis的复制机制(主从复制)

    本篇博客是Redis系列的第4篇,主要讲解下Redis的主从复制机制. 本系列的前3篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安装 Redis系列(二):Redis的5种数据 ...

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

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

  6. 《【面试突击】— Redis篇》-- Redis的主从复制?哨兵机制?

    能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注左上角编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的主从复制?哨兵机制? 在这个 ...

  7. 4、解析配置文件 redis.conf、Redis持久化RDB、Redis的主从复制

    1.Units单位 配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit 对大小写不敏感 2.INCLUDES包含 和我们的Struts2配置文件类似,可以通过includes包 ...

  8. Redis的删除机制、持久化 主从

    转: Redis的删除机制.持久化 主从 Redis的使用分两点: 性能如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存.这样,后面的请求就去缓存中读取 ...

  9. redis的发布订阅、持久化存储、redis的主从复制

    redis的发布订阅 1. 创建redis配置文件 vim /opt/redis_conf/reids-6379.conf mkdir /data/6379 redis-server  redis-6 ...

随机推荐

  1. .NET Core中创建和使用NuGet包

    在.NET Core的项目中,如果我们要在项目中引用其它DLL文件,不应该直接在项目引用中添加DLL文件(虽然在.NET Core项目中也可以这么做),建议是去直接下载DLL文件所属的NuGet包.这 ...

  2. coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介

    RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...

  3. coding++:Linux - Shell - 常用命令

    1.在多个文件中 查找内容 find . -type f -name "*.html" | xargs grep "1"

  4. 为何给CheckBox设置了checked属性还是没有勾选,行内样式都显示了checked

    为何给CheckBox设置了checked属性还是没有勾选,行内样式都显示了checked 正常情况下我们设置给CheckBox一个checked属性后一般都会选中 然而我今天在做案例的时候却遇到了类 ...

  5. iOS 第三方库

    网络 AFNetworking HTTP网络库 Reachability 网络监测 UI.布局 Masonry AutoLayout SnapKit AutoLayout Swift TOWebVie ...

  6. Python itchat库(1)

    一.实验环境 在cmd中输入以下命令,完成微信的API包itchat的安装. pip install itchat 注意这里有个问题,因为电脑里既有Python3.6,又有anaconda.所以一定要 ...

  7. vue组件中的style scoped中遇到的问题

    在uve组件中我们我们经常需要给style添加scoped来使得当前样式只作用于当前组件的节点.添加scoped之后,实际上vue在背后做的工作是将当前组件的节点添加一个像data-v-1233这样唯 ...

  8. vuex知识要点梳理

    该内容为个人总结,请勿喷. 欢迎各位大神前来指点.

  9. html+css实现图片或元素的垂直、水平同时居中的多种方法

    实现元素或图片的上下.左右居中的三种方法 效果图如下: 方法一:利用vertical-align属性实现图片上下居中 先设置父元素样式text-align: center,实现图片左右居中,给图片添加 ...

  10. Java并发基础08. 造成HashMap非线程安全的原因

    在前面我的一篇总结(6. 线程范围内共享数据)文章中提到,为了数据能在线程范围内使用,我用了 HashMap 来存储不同线程中的数据,key 为当前线程,value 为当前线程中的数据.我取的时候根据 ...