深入探讨redis:主从复制

article/2025/6/18 12:58:48

前言

如果某个服务器程序,只部署在一个物理服务器上就可能会面临一下问题(单点问题)

  • 可用性问题,如果这个机器挂了,那么对应的客户端服务也相继断开
  • 性能/支持的并发量有限

所以为了解决这些问题,就要引入分布式系统,在分布式系统中,会在多台服务器上部署redis服务,从而形成一个redis集群,此时就可以让这个集群给整个分布式系统提供更稳定有效的服务。

redis存在多种部署方式

  1. 主从模式
  2. 主从+哨兵模式
  3. 集群模式

主从模式

介绍

在若干个redis节点(物理服务器)中,有的节点被作为主节点,有的则作为从节点分别部署在redis-server进程中,从节点上的数据跟随主节点上的数据变化并保持一致。也就是说如果主节点上保存了一些数据,那么就要将这些数据复制一份出来给从节点,当主节点对这些数据有修改时,从节点也要进行对应的修改,并且从节点上的数据是不能主动或直接修改的,只能读取数据。

//从节点也可以看作是主节点的副本。

通过引入从节点,让我们的服务器有了更多的硬件资源,后续如果有客户端来进行读取数据,就可以在所有节点中随机挑选一个进行读取,因为从节点的数据和主节点的数据是保持一致的,也就可以互相分担更多的请求量,从而提高了服务器的性能

而且引入多台服务器,也能大大提高服务器的稳定性,当有一台机器挂了的时候,还可以访问其他服务器,如果是主节点挂了,那么影响的也只是写操作,读操作依然可以通过从节点进行(主节点只有一个)。但是这种方式只能提高读操作的效率和稳定性,对于写操作因为只能在主节点上完成所以并没有什么提高。

通过单机实现主从模式

虽然主从模式需要多台服务器才能部署,但是我们可以通过在一台机器上,开启多个redis进程服务来模拟一个主从模式,但是这些进程的端口号必须不同。

这里我们来模拟部署一个主节点两个从节点

首先先复制两个配置文件,在配置文件中配置不同的redis端口

mkdir redis-conf
cp /etc/redis/redis.conf ./slave1.conf
cp /etc/redis/redis.conf ./slave2.conf

接着配置端口号

这个daemonize表示让redis按照后台进程的方式来运行

最后运行redis服务器

vim slave1.conf
vim slave2.conf
redis-server ./slave1.conf
redis-server ./slave2.conf

可以看到三个端口都成功运行,但是这只是三个redis服务器,互相独立并没有构成主从结构,想要实现主从结构还需要进一步配置

想要配置成主从结构,需要使用slaveof

  1. 在配置文件中加入slaveof (masterHost) (masterPort)随redis启动时生效
  2. 在redis-server启动命令时加入 --slaveof (masterHost) (masterPort)随redis关闭
  3. 直接使用redis命令:slaveof (masterHost) (masterPort)

这里我们使用配置文件的方式

将两个文件都加上该配置,配置完之后需要重新启动redis,这里世界使用kill -9

netstat -anp | grep redis
kill -9 3748325 3748331

不过这种停止redis-server的方式是和之前直接运行redis-server命令的方式搭配,如果使用的是service redis-server start 的方式启动,就必须使用service redis-server stop停止,因为使用service redis-server start的方式启动的进程,如果使用kill -9杀掉之后,这个redis-server进程会立刻自动重启

 

当重新启动后会看到多了几个tcp连接,这些连接就代表着主从节点直接的连接,每两个是一对。主节点就相当于服务器,从节点就相当于客户端。

//另外一个连接则是单独启动redis-cli来和redis主节点建立的连接

我们来看看到底有没有连上

可以看到我们在6379端口插入的key,在6380依然可以查看到 并且在6380端口不能进行写操作,说明我们已经构建了一个主从模式。

查看redis节点信息

info replication

 主节点信息

  • role:表示是主节点还是从节点
  • connected_slaves:表示该主节点有几个从节点
  • slave:ip:表示从节点地址
  • port:表示从节点端口号
  • state:表示从节点在线状态
  • offset: 表示主节点和从节点之间同步数据的进度
  • lag:表示延迟

从节点信息

可以看到从节点也有 connected_slaves表示从节点也可以有自己的从节点,主从结构不一定就是一个主机连多台从节点,每个从节点也可以再连其他从节点。

断开主从连接

slaveof no one

直接使用这个命令,就会断开当前的主从关系,当从节点断开主节点时,虽然已经不属于这个从节点了,但是里面的数据是不会被删除的,只是后面主节点的数据再发生更改,这个从节点就不会再同步数据了。

主节点

从节点

从信息中可以看到主从节点的关系已经断开,接下来我们实现是否还能同步数据

数据已经无法同步

因为6379和6380已经不是主从节点,所以我们就可以更换6380的主节点

看以看到已经成功把6380的主节点更换成6381,主从模式的结构也发生了改变

此时6380端口的redis服务的数据又和6379一致了,不过虽然此时的6381看起来像是6380的主节点,但是实际上并不是,他仍然是一个从节点不能进行写操作,只是作为6380同步数据的来源。

//刚才通过slaveof修改了主从结构,但是此处的主从结构修改是临时的,如果重启了redis服务器,仍然会变成刚开始的结构,因为我们的配置文件里所配置的结构就是和刚开始的结构一样。

拓扑结构

一主一从

一主一从结构是最简单的复制拓扑结构,用于主节点出现故障时向从节点提供故障转移支持。

这种结构可以帮主节点分担读数据请求,但是如果写数据请求太多,此时也是会给主节点造成不小的压力,可以通过关闭主节点的AOF,只在从节点上开启。也就是只让主节点进行写内存操作,这样就可以减小主节点的压力。

但是这样的设定有一个问题,如果主节点挂了,不能让他自动重启,因为如果自动重启了,此时因为没有AOF文件,就会导致主节点数据丢失,并且因为主从复制,就会把从节点的数据也给删了。所以当主节点挂了之后,应该让主节点先在从节点那里获取AOF文件后,在启动。

一主多从(星形结构)

一种多从的结构方式,可以使节点读写分离,当有大量读请求时可以将请求分摊给各个从节点,还可以让一个从节点专门处理一些比较复杂的读操作以此来提高整体稳定性。

但是主节点上的数据改变时,需要把数据同时同步给所以从节点,也就意味着,随着从节点个数的增加,每次同步数据都会带来更大的开销。而且主从节点之间需要通过网络通信,这就要求主节点有更大的带宽,进而提高整体设备的成本。

树形主从结构

通过这样的结果就可以让主节点有固定的从节点,可以通过从节点来对其他从节点的数据进行同步,但是相应的同步的效率也会变低

主从复制原理 

主从复制流程

  1. 保存主节点信息,开始配置主从同步关系后,从节点只保存主节点的地址信息
  2. 主从节点建立tcp连接(三次握手),从节点内部通过每秒运行的定时任务,维护复制相关逻辑,当定时任务发现存在存在新的主节点后,会尝试与主节点建立基于tcp的网络连接,如果连接失败,定时任务会无限重试直到连接成功或者用户停止主从复制。
  3. 发送ping命令,验证主节点是否正常工作
  4. 如果redis主节点设置了密码(requirepass参数),就要验证权限,从节点通过配置masterauth参数来设置密码。
  5. 同步数据集,主节点会把当前的所有数据全部发送给从节点,这步也是耗时最大的,分为全量同步和部分同步
  6. 命令持续复制,从节点复制主节点数据后,主节点会持续把命令发给从节点,从节点执行修改命令,确保主从数据一致

redis提供了psync replicationid offset命令来完成数据同步,不过一般这个命令是由服务器建立tcp连接后自动执行。

replicationid

这个id是由主节点生成的,每次服务器重启主节点的replicationid都会不同,并且每个主节点有两个id,id1和id2,但是一般只是用id1,从节点和主节点建立关系就会获取主节点的replicationid。另外当从节点通过一些心跳包确定主节点已经挂了的话,就会自己成为主节点,并且给自己生成一个replicationid,但是此时这个节点会通过id2任然记住之前的主节点的id,等到主节点上线后这个节点就可以通过id2再找到原来的主节点

 offset 偏移量

主节点和从节点上都会维护offset偏移量,主节点的偏移量就是,主节点会有很多修改操作,每个命令都会占用几个字节,主节点就会把这些字节累加。从节点的偏移量就描述了同步数据的进度,如果从节点和主节点的replicationid和offset偏移量都一样,就可以认为主从节点数据一致。

psync流程 

从节点发送psync命令给主节点,主节点会根据psync的参数(id和offset)以及自身数据情况决定响应情况。

  • FULLRESYNC:全量数据同步
  • CONTINFU:增量数据同步
  • -ERR:比较老版本的redis不支持psync

psync可以从主节点获取全部数据也可以获得部分数据主要看参数offset,如果是-1(默认)的话就是获取全量数据,如果是一个具体的值就是部分复制而且从当前偏移量开始复制,不过也不是从节点想从哪个地方复制就从那个地方复制,主节点也会根据实际判断。

什么时候全量复制

  • 首次和主节点进行数据同步
  • 主节点不方便进行部分复制

什么时候部分复制

  • 从节点已经从主节点上复制过数据了,因为一些原因断开连接了,从节点需要重新从主节点这边同步数据,此时因为从节点上已经有数据了所以只需要复制一部分就行

全量复制流程

1)从节点发送psync命令向主节点要数据,因为是第一次进行复制则psync参数就是(?,-1)表示进行全量复制。

2)主节点收到命令解析后回复FULLRESYNC响应

3)从节点收到响应后会保存主节点的运行信息

4)之后主节点会自动执行bgsave命令,进行快照操作完成持久化,并复制出一个新的rdb文件。(因为从节点的数据和主节点的数据要求完全同步,所以必须使用新的rdb文件以保证数据的实时性)

5)主节点将新复制的rdb文件传输给从节点(因为复制rdb文件是一个较高消耗的操作,而且这次是全量复制所以要传输的数据也比较多,所以整体过程较为耗时。就会导致在这个过程中会有新的修改命令,那么我们从节点接收到的rdb文件就不是最新的了)

6)因为无法保证传输的rdb文件是最新的,所以主节点会将复制和传输rdb文件期间接收到的写命令放入一个缓冲区,当从节点保存完rdb文件后,主节点就会将缓冲区中的数据传输给从节点,这些数据任然是按照rdb的二进制格式追加到从节点的rdb文件中,以保证主从节点数据的完全一致。

7)从节点清除自身的旧数据

8)从节点加载rdb文件

9)如果从节点开启了AOF,那么在加载的时候就会产生大量的aof日志,因为全量复制的数据量很大就会出现很多冗余的日志,因此这里就会执行bgrewriteaof,将aof文件里该删的删,该合并的合并,对文件进行一个整理。

无硬盘模式全量复制

在刚刚的流程中主节点复制一份新的rdb文件目的就是为了,将数据传输给从节点,那么为了节省开销,就可以省去这个读写硬盘的操作(复制rdb),直接将数据通过网络传输给从节点,这样就节省了一次复制rdb的时间,从节点接收到数据后也是写入到rdb文件然后加载数据,那么将这个过程也省略掉,直接把收到的数据进行加载,这样就又省了一系列读写硬盘的操作

部分复制流程

当主从节点都正常工作一段时间后,此时从节点已经有了主节点的复制,如果在某一时刻因为网络抖动,或者其他原因主从节之间的连接断开了的话,后续再连接上就只需要进行部分复制(具体连接过程上文有提到)。

1)如果主从节点断开的时间超过repi-timeout设定的时间,那么主节点就认为从节点断开了

2)从节点在断开连接时依然会响应命令,但是由于这些复制命令发不出去都会放在一个积压缓冲区里(一个用数组实现的环形队列)

3)重新连接后,从节点会根据之前保存的主节点的replicationid和offset通过psync的参数发送给主节点 

4)主节点接收到psync命令后会对replicationid和offset(描绘的就是主从节点的复制进度)进行判断,如果replicationid不是自己的replicationid主节点就会认为这个从节点是新连接上的就会进行全量复制,如果replicationid正确则进行部分复制。判断offset的值,主要是判断从节点当前的复制进度是多少,如果从节点当前缺失的部分刚好是积压缓冲区里的数据,就可以直接将这部分数据复制过去,如果不是则需要将之前缺失的数据也复制过去,最后主节点还要响应CONTINUE表示这是一次部分复制。

实时复制

从节点已经和主节点同步好了数据,但是主节点依然会又源源不断的新的请求,主节点的数据改变,从节点的数据也就要改变。

主从节点之间会通过TCP建立长连接,然后主节点会把自己收到的修改数据的请求通过连接发送给从节点,从节点在根据这些请求修改自己的数据。(如果主从结构是树型的那么发送的过程就会较为耗时)

因为在实时复制时,主从节点需要保证连接的稳定,就会通过心跳机制来确定对方是否正常在线。

  • 主节点:默认是每10s给从节点发送一个ping命令,从节点收到后就会返回pong
  • 从节点:默认每个1s就给主节点发送一个特殊的请求,就会通知主节点自己当前的复制进度offset

总结 

全量复制的部分复制都是在从节点第一次连接主节点时进行的,如果以前没连过就进行全量复制,如果连接过又断开的就进行部分复制,也就是说全量复制和部分复制都是给从节点进行一个初始化的。而后续的主从节点间数据的同步则是通过实时复制。


http://www.hkcw.cn/article/xqqqWCyOXZ.shtml

相关文章

c++ typeid运算符

typeid运算符能获取类型信息。获取到的是type_info对象。type_info类型如下: 可以看到,这个类删除了拷贝构造函数以及等号操作符。有一些成员函数:hash_code、before、name、raw_name, 还重载了和!运算符。 测试: void testTyp…

一人住院不必全家奔波!免陪照护试点“全国版”

俗话说“久病床前无孝子”,这句话道出了很多家庭面对病人陪护时的无奈与压力。特别是现在每个人都在谈论的老龄化,再叠加上独生子女,父母住院时的陪护,就更是个越来越难的难题。这时候,如果能由医院来提供标准化的照护服务,估计很多人听了都会有一种如释重负的感觉。随着…

F1西班牙站排位赛:皮亚斯特里夺杆位,迈凯伦强势领跑

北京时间5月31日,F1西班牙大奖赛排位赛落下帷幕。皮亚斯特里夺得杆位,诺里斯和维斯塔潘分列二、三位。拉塞尔排名第四,汉密尔顿第五,安东内利第六,勒克莱尔第七,加斯利第八,哈贾尔第九,阿隆索第十。阿尔本第十一,塞恩斯第十八,科拉平托第十九,角田裕毅第二十。在首轮…

哈马斯回应加沙停火提案 美称“不可接受”

哈马斯回应加沙停火提案 美称“不可接受” 以称继续行动△美国中东问题特使威特科夫(资料图)央视记者获悉,特朗普政府提出的一项旨在促成加沙停火的新一轮提案,遭到巴勒斯坦伊斯兰抵抗运动(哈马斯)的修改要求。对此,美国中东问题特使威特科夫当地时间5月31日公开表示,哈…

uniapp与微信小程序开发平台联调无法打开IDE

经测试属于网络问题。本机需要联网。否则会出现Hbuilder运行微信小程序到模拟器时无法打开 微信开发者工具 这个页面出不来会一直显示异常。这期间微信小程序开发工具的端口是通的 需要先联网

Deseq2:MAG相对丰度差异检验

首先使用代码将contigs和MAG联系起来 https://github.com/MrOlm/drep/blob/master/helper_scripts/parse_stb.py ~/parse_stb.py --reverse -f ~/bin_dir/* -o ~/bin_dir/genomes.stb # 查看第一列的contigs有没有重复(重复的话会影响后续比对) awk {p…

自动驾驶系列—Monocular 3D Lane Detection for Autonomous Driving

🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中…

这纳米手套能「传触感」,98% 准度+无线震动反馈

*本文只做阅读笔记分享* 一、研究背景与挑战 今天我们聚焦一项针对上肢感觉障碍的创新康复技术。创伤性脊髓损伤(TSCI)在儿童群体中危害显著,因其神经系统尚未发育成熟,常导致患肢失用、对侧肢体过度使用等问题。当前传统疗法如…

Java基础学习

输入输出 import java.util.*; public class Main {public static void main(String[] args) {int s 888;String s1 "Hello World"; // System.out.print(s); // System.out.print(s1);System.out.println(s);System.out.println(s1);Scanner sc ne…

异构边缘智能处理加速板

简介: TC-ATLAS200-K7325TI是一套FPGAGPU架构的异构边缘智能处理加速板。该板基于华为 ATLAS200 GPU及Xilinx K7高性能FPGA(可替换为复旦微JFM7K325T)设计而成。 GPU与FPGA之间通过PCIE2.0 X4 互连,实现两者之间数据的高速传输。板…

进程间通信(消息队列)

目录 一 原理 二 API 1. ftok 2. msgget 3. msgctl 4. msgsnd 5. msgrcv 三 demo代码 四 基于责任链模式和消息队列对数据处理 1. 什么是责任链模式 2. 下面基于责任链模式来对消息队列获取的消息进行处理 前置 其实system v 版本的进程间通信,设计的接…

解决8080端口被占问题

文章目录 1. 提出问题2. 解决问题2.1 查看占用8080端口的进程2.2 杀死占用8080端口的进程2.3 测试问题是否已解决3. 实战小结1. 提出问题 运行Spring Boot项目,报错8080端口被占 2. 解决问题 2.1 查看占用8080端口的进程 执行命令:netstat -ano | findstr :8080 2.2 杀死占用…

【harbor】--基础使用

推送 不同的管理工具都有说明 以docker为例 # 第一步--打标签 docker tag SOURCE_IMAGE[:TAG] 192.168.121.201:801/haohao_fist/REPOSITORY[:TAG] # 第二步--推送 docker push 192.168.121.201:801/haohao_fist/REPOSITORY[:TAG]默认push推送为https push会失败 解决办法…

论文略读:To the Globe (TTG): Towards Language-Driven Guaranteed Travel Planning

2024 Emnlp demo 提出了TTG,一个演示系统,它能够接收用户的自然语言指令,并在几秒钟内生成最优的旅行行程 结合了大语言模型(LLMs,Llama-3 70B)与现有的符号求解器(例如混合整数线性规划&#…

《操作系统真相还原》——初探保护模式

BUG 果不其然出现bug b 0x900在进入loader的时候打个断点,看看什么情况,好吧突然想起来,可能弄错镜像了 重新执行 正确 info gdt看一下相关信息

[yolov11改进系列]基于yolov11引入高效坐标注意力机制CoordAttention的python源码+训练源码

【CoordAttention介绍】 在轻量级网络上的研究表明,通道注意力会给模型带来比较显著的性能提升,但是通道注意力通常会忽略对生成空间选择性注意力图非常重要的位置信息。因此,新加坡国立大学的提出了一种为轻量级网络设计的新的注意力机制&a…

AI Agent的“搜索大脑“进化史:从Google API到智能搜索生态的技术变革

AI Agent搜索革命的时代背景 2025年agent速度发展之快似乎正在验证"2025年是agent元年"的说法,而作为agent最主要的应用工具之一(另外一个是coding),搜索工具也正在呈现快速的发展趋势。Google在2024年12月推出Gemini Deep Research&#xff0…

以防长:辛瓦尔已死 这些人是下个目标

当地时间5月31日,以色列国防军发表声明,确认在以色列国防军与以色列国家安全总局(辛贝特)今年5月13日的联合行动中,以色列空军对巴勒斯坦伊斯兰抵抗运动(哈马斯)军事领导人穆罕默德辛瓦尔发动空袭并将其打死。以军声明称,此次空袭还打死了包括哈马斯拉法旅指挥官穆罕默…

8旬老人砍掉小区20年香樟树 私自修剪引发争议

家住浦东新区上南山水苑一期的业主王先生反映,小区内一群平均年龄七十多岁的老人以提高绿化环境为由,私自圈占公共绿化变为私人花园已有两年。物业和居委会多次劝阻无效,老人们的花越种越多。本周二上午,一位老人用网购的斧头和电锯砍伐了小花园内一棵20多年的香樟树。投诉…

代码随想录算法训练营第60期第五十三天打卡

大家好,我们今天来到了最后一章图论,其实图论比较难,涉及的算法也比较多,今天比较重要的就是深度优先搜索与广度优先搜索,后面的迪杰斯特拉算法等算法在我们求最短路都会涉及到,还有最近公共祖先&#xff0…