redis 主存复制

news/2024/11/29 8:43:29/

1. 前言

Redis的持久化机制,它很好的解决了单台Redis服务器由于意外情况导致Redis服务器进程退出或者Redis服务器宕机而造成的数据丢失问题

在一定程度上保证了数据的安全性,即便是服务器宕机的情况下,也可以保证数据的丢失非常少。

通常,为了避免服务的单点故障,会把数据复制到多个副本放在不同的服务器上,且这些拥有数据副本的服务器可以用于处理客户端的读请求,扩展整体的性能。

单台Redis的性能再好,但单台毕竟还是有瓶颈的,使用主从复制可以实现读写分离,提高Redis的高可用性,即主服务器用来执行写命令,多个从服务器用来执行读命令,类似于数据库的读写分离

官方文档:https://redis.io/docs/management/replication/

2. 夯实基础

2.1 什么是主存复制

主存复制,就是master以写为主,slave以读为主,当master数据变化的时候,自动将新的数据异步同步到其它slave数据库。

这个模式可以保证多台服务器的数据一致性,且主从服务器之间采用的是「读写分离」的方式。

主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令,然后执行这条命令。

在这里插入图片描述
也就是说,所有的数据修改只在主服务器上进行,然后将最新的数据同步给从服务器,这样就使得主从服务器的数据是一致的。

主要功能特性

  1. 读写分离
  2. 容灾恢复
  3. 数据备份
  4. 水平扩容支持高并发

2.2 基本操作命令

1)info replication
可以查看复制节点的主从关系和配置信息

2)replicaof 主库IP 主库端口
设置主库节点,一般写入仅redis.conf配置文件内

3)slaveof 主库IP 主库端口
与主库绑定的存库,每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件。
在运行期间修改slave节点的信息,如果该数据库已经是某个主数据库的从数据库,那么会停止和原主数据库的同步关系转而和新的主数据库同步,重新拜码头。

4)slaveof no one
使当前数据库停止与其他数据库同步,转成主数据库,自立为王

2.3 复制原理和工作流程

2.3.1 slave 首次次启动同步

多台服务器之间要通过什么方式来确定谁是主服务器,或者谁是从服务器呢?

我们可以使用 replicaof(Redis 5.0 之前使用 slaveof)命令形成主服务器和从服务器的关系。

比如,现在有服务器 A 和 服务器 B,我们在服务器 B 上执行下面这条命令:

# 服务器 B 执行这条命令
replicaof <服务器 A 的 IP 地址> <服务器 A 的 Redis 端口号>

接着,服务器 B 就会变成服务器 A 的「从服务器」,然后与主服务器进行第一次同步。

主从服务器间的第一次同步的过程可分为三个阶段:

  • 第一阶段是建立链接、协商同步;
  • 第二阶段是主服务器同步数据给从服务器;
  • 第三阶段是主服务器发送新写操作命令给从服务器。

为了让你更清楚了解这三个阶段,我画了一张图。
在这里插入图片描述
接下来,我在具体介绍每一个阶段都做了什么。

第一阶段:建立链接、协商同步

执行了 replicaof 命令后,从服务器就会给主服务器发送 psync 命令,表示要进行数据同步。

psync 命令包含两个参数,分别是主服务器的 runID复制进度 offset

  • runID,每个 Redis 服务器在启动时都会自动生产一个随机的 ID 来唯一标识自己。当从服务器和主服务器第一次同步时,因为不知道主服务器的 run ID,所以将其设置为 “?”。
  • offset,表示复制的进度,第一次同步时,其值为 -1。

主服务器收到 psync 命令后,会用 FULLRESYNC 作为响应命令返回给对方。

并且这个响应命令会带上两个参数:主服务器的 runID 和主服务器目前的复制进度 offset。从服务器收到响应后,会记录这两个值。

FULLRESYNC 响应命令的意图是采用全量复制的方式,也就是主服务器会把所有的数据都同步给从服务器。

所以,第一阶段的工作时为了全量复制做准备。

那具体怎么全量同步呀呢?我们可以往下看第二阶段。

第二阶段:主服务器同步数据给从服务器

接着,主服务器会执行 bgsave 命令来生成 RDB 文件,然后把文件发送给从服务器。

从服务器收到 RDB 文件后,会先清空当前的数据,然后载入 RDB 文件。

这里有一点要注意,主服务器生成 RDB 这个过程是不会阻塞主线程的,因为 bgsave 命令是产生了一个子进程来做生成 RDB 文件的工作,是异步工作的,这样 Redis 依然可以正常处理命令。

但是,这期间的写操作命令并没有记录到刚刚生成的 RDB 文件中,这时主从服务器间的数据就不一致了。

那么为了保证主从服务器的数据一致性,主服务器在下面这三个时间间隙中将收到的写操作命令,写入到 replication buffer 缓冲区里

  1. 主服务器生成 RDB 文件期间;
  2. 主服务器发送 RDB 文件给从服务器期间;
  3. 「从服务器」加载 RDB 文件期间;

第三阶段:主服务器发送新写操作命令给从服务器

在主服务器生成的 RDB 文件发送完,从服务器收到 RDB 文件后,丢弃所有旧数据,将 RDB 数据载入到内存。完成 RDB 的载入后,会回复一个确认消息给主服务器。

接着,主服务器将 replication buffer 缓冲区里所记录的写操作命令发送给从服务器,从服务器执行来自主服务器 replication buffer 缓冲区里发来的命令,这时主从服务器的数据就一致了。

至此,主从服务器的第一次同步的工作就完成了。

2.3.2 命令传播

主从服务器在完成第一次同步后,双方之间就会维护一个 TCP 连接。
在这里插入图片描述
后续主服务器可以通过这个连接继续将写操作命令传播给从服务器,然后从服务器执行该命令,使得与主服务器的数据库状态相同。

而且这个连接是长连接的,目的是避免频繁的 TCP 连接和断开带来的性能开销。

上面的这个过程被称为基于长连接的命令传播,通过这种方式来保证第一次同步后的主从服务器的数据一致性。

2.3.3 增量复制

主从服务器在完成第一次同步后,就会基于长连接进行命令传播。

可是,网络总是不按套路出牌的嘛,说延迟就延迟,说断开就断开。

如果主从服务器间的网络连接断开了,那么就无法进行命令传播了,这时从服务器的数据就没办法和主服务器保持一致了,客户端就可能从「从服务器」读到旧的数据。
在这里插入图片描述
那么问题来了,如果此时断开的网络,又恢复正常了,要怎么继续保证主从服务器的数据一致性呢?

在 Redis 2.8 之前,如果主从服务器在命令同步时出现了网络断开又恢复的情况,从服务器就会和主服务器重新进行一次全量复制,很明显这样的开销太大了,必须要改进一波。

所以,从 Redis 2.8 开始,网络断开又恢复后,从主从服务器会采用增量复制的方式继续同步,也就是只会把网络断开期间主服务器接收到的写操作命令,同步给从服务器。

网络恢复后的增量复制过程如下图:
在这里插入图片描述
主要有三个步骤:

  1. 从服务器在恢复网络后,会发送 psync 命令给主服务器,此时的 psync 命令里的 offset 参数不是 -1;
  2. 主服务器收到该命令后,然后用 CONTINUE 响应命令告诉从服务器接下来采用增量复制的方式同步数据;
  3. 然后主服务将主从服务器断线期间,所执行的写命令发送给从服务器,然后从服务器执行这些命令。

那么关键的问题来了,主服务器怎么知道要将哪些增量数据发送给从服务器呢

答案藏在这两个东西里:

  1. repl_backlog_buffer,是一个「环形」缓冲区,用于主从服务器断连后,从中找到差异的数据;
  2. replication offset,标记上面那个缓冲区的同步进度,主从服务器都有各自的偏移量,主服务器使用 master_repl_offset 来记录自己「写」到的位置,从服务器使用 slave_repl_offset 来记录自己「读」到的位置。

那 repl_backlog_buffer 缓冲区是什么时候写入的呢?

在主服务器进行命令传播时,不仅会将写命令发送给从服务器,还会将写命令写入到 repl_backlog_buffer 缓冲区里,因此 这个缓冲区里会保存着最近传播的写命令。

网络断开后,当从服务器重新连上主服务器时,从服务器会通过 psync 命令将自己的复制偏移量 slave_repl_offset 发送给主服务器,主服务器根据自己的 master_repl_offset 和 slave_repl_offset 之间的差距,然后来决定对从服务器执行哪种同步操作:

  • 如果判断出从服务器要读取的数据还在 repl_backlog_buffer 缓冲区里,那么主服务器将采用增量同步的方式;
  • 相反,如果判断出从服务器要读取的数据已经不存在 repl_backlog_buffer 缓冲区里,那么主服务器将采用全量同步的方式。

当主服务器在 repl_backlog_buffer 中找到主从服务器差异(增量)的数据后,就会将增量的数据写入到 replication buffer 缓冲区,这个缓冲区我们前面也提到过,它是缓存将要传播给从服务器的命令。

在这里插入图片描述
repl_backlog_buffer 缓行缓冲区的默认大小是 1M,并且由于它是一个环形缓冲区,所以当缓冲区写满后,主服务器继续写入的话,就会覆盖之前的数据。因此,当主服务器的写入速度远超于从服务器的读取速度,缓冲区的数据一下就会被覆盖。

那么在网络恢复时,如果从服务器想读的数据已经被覆盖了,主服务器就会采用全量同步,这个方式比增量同步的性能损耗要大很多。

因此,为了避免在网络恢复时,主服务器频繁地使用全量同步的方式,我们应该调整下 repl_backlog_buffer 缓冲区大小,尽可能的大一些,减少出现从服务器要读取的数据被覆盖的概率,从而使得主服务器采用增量同步的方式。

那 repl_backlog_buffer 缓冲区具体要调整到多大呢?

repl_backlog_buffer 最小的大小可以根据这面这个公式估算。
在这里插入图片描述

  • second 为从服务器断线后重新连接上主服务器所需的平均 时间(以秒计算)。
  • write_size_per_second 则是主服务器平均每秒产生的写命令数据量大小。

举个例子,如果主服务器平均每秒产生 1 MB 的写命令,而从服务器断线之后平均要 5 秒才能重新连接主服务器。

那么 repl_backlog_buffer 大小就不能低于 5 MB,否则新写地命令就会覆盖旧数据了。

当然,为了应对一些突发的情况,可以将 repl_backlog_buffer 的大小设置为此基础上的 2 倍,也就是 10 MB。

关于 repl_backlog_buffer 大小修改的方法,只需要修改配置文件里下面这个参数项的值就可以。

repl-backlog-size 1mb

3. 常见面试题及解析

3.1 Redis主从节点时长连接还是短连接?

长链接,避免TCP连接断开重连的消耗

3.2 怎么判断 Redis 某个节点是否正常工作?

Redis 判断节点是否正常工作,基本都是通过互相的 ping-pong 心态检测机制,如果有一半以上的节点去 ping 一个节点的时候没有 pong 回应,集群就会认为这个节点挂掉了,会断开与这个节点的连接。

Redis 主从节点发送的心跳间隔是不一样的,而且作用也有一点区别:

  • Redis 主节点默认每隔 10 秒对从节点发送 ping 命令,判断从节点的存活性和连接状态,可通过参数repl-ping-slave-period控制发送频率。
  • Redis 从节点每隔 1 秒发送 replconf ack{offset} 命令,给主节点上报自身当前的复制偏移量,目的是为了:
    • 实时监测主从节点网络状态;
    • 上报自身复制偏移量, 检查复制数据是否丢失, 如果从节点数据丢失, 再从主节点的复制缓冲区中拉取丢失数据。

3.3. 主从复制架构中,过期key如何处理?

主节点处理了一个key或者通过淘汰算法淘汰了一个key,这个时间主节点模拟一条del命令发送给从节点,从节点收到该命令后,就进行删除key的操作。

3.4 Redis 是同步复制还是异步复制?

Redis 主节点每次收到写命令之后,先写到内部的缓冲区,然后异步发送给从节点。

3.5 主从复制中两个 Buffer(replication buffer 、repl backlog buffer)有什么区别?

replication buffer 、repl backlog buffer 区别如下:

  • 出现的阶段不一样:
    • repl backlog buffer 是在增量复制阶段出现,一个主节点只分配一个 repl backlog buffer;
    • replication buffer 是在全量复制阶段和增量复制阶段都会出现,主节点会给每个新连接的从节点,分配一个 replication buffer;
  • 这两个 Buffer 都有大小限制的,当缓冲区满了之后,发生的事情不一样:
    • 当 repl backlog buffer 满了,因为是环形结构,会直接覆盖起始位置数据;
    • 当 replication buffer 满了,会导致连接断开,删除缓存,从节点重新连接,重新开始全量复制。

3.6 如何应对主从数据不一致?

为什么会出现主从数据不一致?

主从数据不一致,就是指客户端从从节点中读取到的值和主节点中的最新值并不一致。

之所以会出现主从数据不一致的现象,是因为主从节点间的命令复制是异步进行的,所以无法实现强一致性保证(主从数据时时刻刻保持一致)。

具体来说,在主从节点命令传播阶段,主节点收到新的写命令后,会发送给从节点。但是,主节点并不会等到从节点实际执行完命令后,再把结果返回给客户端,而是主节点自己在本地执行完命令后,就会向客户端返回结果了。如果从节点还没有执行主节点同步过来的命令,主从节点间的数据就不一致了。

如何如何应对主从数据不一致?

第一种方法,尽量保证主从节点间的网络连接状况良好,避免主从节点在不同的机房。

第二种方法,可以开发一个外部程序来监控主从节点间的复制进度。具体做法:

  • Redis 的 INFO replication 命令可以查看主节点接收写命令的进度信息(master_repl_offset)和从节点复制写命令的进度信息(slave_repl_offset),所以,我们就可以开发一个监控程序,先用 INFO replication 命令查到主、从节点的进度,然后,我们用 master_repl_offset 减去 slave_repl_offset,这样就能得到从节点和主节点间的复制进度差值了。
  • 如果某个从节点的进度差值大于我们预设的阈值,我们可以让客户端不再和这个从节点连接进行数据读取,这样就可以减少读到不一致数据的情况。不过,为了避免出现客户端和所有从节点都不能连接的情况,我们需要把复制进度差值的阈值设置得大一些。

3.7 主从切换如何减少数据丢失?

主从切换过程中,产生数据丢失的情况有两种:

  • 异步复制同步丢失
  • 集群产生脑裂数据丢失

我们不可能保证数据完全不丢失,只能做到使得尽量少的数据丢失。

异步复制同步丢失

对于 Redis 主节点与从节点之间的数据复制,是异步复制的,当客户端发送写请求给主节点的时候,客户端会返回 ok,接着主节点将写请求异步同步给各个从节点,但是如果此时主节点还没来得及同步给从节点时发生了断电,那么主节点内存中的数据会丢失。

3.8 主从如何做到故障自动切换?

主节点挂了 ,从节点是无法自动升级为主节点的,这个过程需要人工处理,在此期间 Redis 无法对外提供写操作。

此时,Redis 哨兵机制就登场了,哨兵在发现主节点出现故障时,由哨兵自动完成故障发现和故障转移,并通知给应用方,从而实现高可用性。

4. 总结

主从复制共有三种模式:全量复制基于长连接的命令传播增量复制

主从服务器第一次同步的时候,就是采用全量复制,此时主服务器会两个耗时的地方,分别是生成 RDB 文件和传输 RDB 文件。为了避免过多的从服务器和主服务器进行全量复制,可以把一部分从服务器升级为「经理角色」,让它也有自己的从服务器,通过这样可以分摊主服务器的压力。

第一次同步完成后,主从服务器都会维护着一个长连接,主服务器在接收到写操作命令后,就会通过这个连接将写命令传播给从服务器,来保证主从服务器的数据一致性。

如果遇到网络断开,增量复制就可以上场了,不过这个还跟 repl_backlog_size 这个大小有关系。

如果它配置的过小,主从服务器网络恢复时,可能发生「从服务器」想读的数据已经被覆盖了,那么这时就会导致主服务器采用全量复制的方式。所以为了避免这种情况的频繁发生,要调大这个参数的值,以降低主从服务器断开后全量同步的概率。


http://www.ppmy.cn/news/1112942.html

相关文章

python经典百题之各项数想加之和

题目&#xff1a;求saaaaaaaaaaaa...a的值&#xff0c;其中a是一个数字。例如222222222222222(此时 共有5个数相加)&#xff0c;几个数相加有键盘控制。 方法一&#xff1a;循环累加 思路&#xff1a;通过循环实现累加&#xff0c;将每一项的值计算出来并累加到总和中。具体…

丙烯酸共聚聚氯乙烯树脂

声明 本文是学习GB-T 42790-2023 丙烯酸共聚聚氯乙烯树脂. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了丙烯酸共聚聚氯乙烯树脂的外观、物化性能等技术要求&#xff0c;描述了相应的采样、试验方 法、检验规则、标志、包装、…

【React】React入门

目录 一、何为React二、React与传统MVC的关系三、React的特性1、声明式编程①、实现标记地图 2、高效灵活3、组件式开发(Component)①、函数式组件②、类组件&#xff08;有状态组件&#xff09;③、一个组件该有的特点 4、单向式响应的数据流 四、虚拟DOM1、传统DOM更新①、举…

【python爬虫—星巴克产品】

文章目录 需求爬取星巴克产品以及图片&#xff0c;星巴克菜单 python爬虫爬取结果 需求 爬取星巴克产品以及图片&#xff0c;星巴克菜单 网页分析&#xff1a; 首先&#xff0c;需要分析星巴克官方网站的结构&#xff0c;了解菜单栏的位置、布局以及菜单项的标签或类名等信息…

【自用】深度学习工作站安装ubuntu 18.04 LTS系统

工作站配置&#xff1a; 自己组装的 主板&#xff1a;华硕Z790P&#xff08;PCIE插槽间距大&#xff0c;可以装双显卡&#xff09; CPU&#xff1a;i5 13600KF 内存&#xff1a;32 G 显卡&#xff1a;GTX 2080 Ti &#xff08;魔改版&#xff0c;22G&#xff09; 存储&#xf…

office mac苹果办公软件安装包安装教程详解

软件下载 软件&#xff1a;mac office版本&#xff1a;2021语言&#xff1a;简体中文大小&#xff1a;4.27G安装环境&#xff1a;mac硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff09;下载通道 百度网盘 https://pan.baidu.com/s/1WGSB-icELUxweFkI8iIbzA 首先&#…

改进YOLOv5小目标检测:构建多尺度骨干和特征增强模块,提升小目标检测

构建多尺度骨干和特征增强模块,提升小目标检测 背景代码使用配置文件如下🔥🔥🔥 提升小目标检测,创新提升 🔥🔥🔥 测试在小目标数据集进行提点 👉👉👉: 新设计的创新想法,包含详细的代码和说明,具备有效的创新组合 🐤🐤🐤 1. 本文包含两个创新改…

Vulnhub实战-DC9

前言 本次的实验靶场是Vulnhub上面的DC-9&#xff0c;其中的渗透测试过程比较多&#xff0c;最终的目的是要找到其中的flag。 一、信息收集 对目标网络进行扫描 arp-scan -l 对目标进行端口扫描 nmap -sC -sV -oA dc-9 192.168.1.131 扫描出目标开放了22和80两个端口&a…