深入探讨redis:主从复制

前言

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

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

所以为了解决这些问题,就要引入分布式系统,在分布式系统中,会在多台服务器上部署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.pswp.cn/pingmian/83039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MacOS安装Docker Desktop并汉化

1. 安装Docker Desktop 到Docker Desktop For Mac下载对应系统的Docker Desktop 安装包,下载后安装,没有账号需要注册,然后登陆即可。 2. 汉化 前往汉化包下载链接下载对应系统的.asar文件 然后将安装好的文件覆盖原先的文件app.asar文件…

索引的选择与Change Buffer

1. 索引选择与Change Buffer 问题引出:普通索引 vs 唯一索引 ——如何选择? 在实际业务中,如果一个字段的值天然具有唯一性(如身份证号),并且业务代码已确保无重复写入,那就存在两种选择&…

lua注意事项

感觉是lua的一大坑啊,它还不如函数内部就局部变量呢 注意函数等内部,全部给加上local得了

【多线程初阶】死锁的产生 如何避免死锁

文章目录 关于死锁一.死锁的三种情况1.一个线程,一把锁,连续多次加锁2.两个线程,两把锁3.N个线程,M把锁 --哲学家就餐问题 二.如何避免死锁死锁是如何构成的(四个必要条件)打破死锁 三.死锁小结 关于死锁 一.死锁的三种情况 1.一个线程,一把锁,连续多次加锁 -->由synchroni…

【NLP基础知识系列课程-Tokenizer的前世今生第二课】NLP 中的 Tokenizer 技术发展史

从词表到子词:Tokenizer 的“进化树” 我们常说“语言模型是理解人类语言的工具”,但事实上,模型能不能“理解”,关键要看它接收到了什么样的输入。而 Tokenizer,就是这一输入阶段的设计者。 在 NLP 的发展历程中&am…

Rust 学习笔记:循环和迭代器的性能比较

Rust 学习笔记:循环和迭代器的性能比较 Rust 学习笔记:循环和迭代器的性能比较示例 1示例 2总结 Rust 学习笔记:循环和迭代器的性能比较 示例 1 我们运行一个基准测试,将《福尔摩斯探案集》的全部内容加载到一个字符串中&#x…

pod创建和控制

一、引言 ‌主题‌:pod以及控制器模式中的Deployment作用。‌控制器模式:使用一种API对象(如Deployment)管理另一种API对象(如Pod)的方式。 二、容器镜像与配置文件 ‌容器镜像‌:应用开发者…

HTML实战:爱心图的实现

设计思路 使用纯CSS创建多种风格的爱心 添加平滑的动画效果 实现交互式爱心生成器 响应式设计适应不同设备 优雅的UI布局和色彩方案 <!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8"> <meta nam…

2022年 中国商务年鉴(excel电子表格版)

2022年 中国商务年鉴&#xff08;excel电子表格版&#xff09;.ziphttps://download.csdn.net/download/2401_84585615/89772883 https://download.csdn.net/download/2401_84585615/89772883 《中国商务年鉴2022》是由商务部国际贸易经济合作研究院主办的年度统计资料&#xf…

Redis核心数据结构操作指南:字符串、哈希、列表详解

注&#xff1a;此为苍穹外卖学习笔记 Redis作为高性能的键值数据库&#xff0c;其核心价值来自于丰富的数据结构支持。本文将深入解析字符串&#xff08;String&#xff09;、哈希&#xff08;Hash&#xff09;、**列表&#xff08;List&#xff09;**三大基础结构的操作命令&…

如何以 9 种方式将照片从 iPhone 传输到笔记本电脑

您的 iPhone 可能充满了以照片和视频形式捕捉的珍贵回忆。无论您是想备份它们、在更大的屏幕上编辑它们&#xff0c;还是只是释放设备上的空间&#xff0c;您都需要将照片从 iPhone 传输到笔记本电脑。幸运的是&#xff0c;有 9 种方便的方法可供使用&#xff0c;同时满足 Wind…

如何使用Python从MySQL数据库导出表结构到Word文档

在开发和维护数据库的过程中&#xff0c;能够快速且准确地获取表结构信息是至关重要的。本文将向您展示一种简单而有效的方法&#xff0c;利用Python脚本从MySQL数据库中提取指定表的结构信息&#xff0c;并将其导出为格式化的Word文档。此方法不仅提高了工作效率&#xff0c;还…

写作-- 复合句练习

文章目录 练习 11. 家庭的支持和老师的指导对学生的学术成功有积极影响。2. 缺乏准备和未能适应通常会导致在挑战性情境中的糟糕表现。3. 吃垃圾食品和忽视锻炼可能导致严重的健康问题,因此人们应注重保持均衡的生活方式。4. 昨天的大雨导致街道洪水泛滥,因此居民们迁往高地以…

QT使用说明

QT环境准备 推荐Ubuntu平台上使用&#xff0c;配置简单&#xff0c;坑少。 Ubuntu 20.04 安装 sudo apt-get install qt5-default -y sudo apt-get install qtcreator -y sudo apt-get install -y libclang-common-8-dev启动 qtcreatorHelloWorld 打开 Qt Creator。选择 …

React 第四十九节 Router中useNavigation的具体使用详解及注意事项

前言 useNavigation 是 React Router 中一个强大的钩子&#xff0c;用于获取当前页面导航的状态信息。 它可以帮助开发者根据导航状态优化用户体验&#xff0c;如显示加载指示器、防止重复提交等。 一、useNavigation核心用途 检测导航状态&#xff1a;判断当前是否正在进行…

列表单独展开收起同时关闭其余子项的问题优化

如图所示&#xff0c;当在列表中&#xff0c;需要分别单独点开子选项时&#xff0c;直接这样用一个index参数判断即可&#xff0c;非常简单方便&#xff0c;只需要满足点开当前index,然后想同index用null值自动关闭即可

WPF【11_5】WPF实战-重构与美化(MVVM 实战)

11-10 【重构】创建视图模型&#xff0c;显示客户列表 正式进入 MVVM 架构的代码实战。在之前的课程中&#xff0c; Model 和 View 这部分的代码重构实际上已经完成了。 Model 就是在 Models 文件夹中看到的两个文件&#xff0c; Customer 和 Appointment。 而 View 则是所有与…

LangChain-结合魔塔社区modelscope的embeddings实现搜索

首先要安装modelscope pip install modelscope 安装完成后测试 from langchain_community.embeddings import ModelScopeEmbeddingsembeddings ModelScopeEmbeddings(model_id"iic/nlp_gte_sentence-embedding_chinese-base")text "这是一个测试句子"…

可定制化货代管理系统,适应不同业务模式需求!

在全球化贸易的浪潮下&#xff0c;货运代理行业扮演着至关重要的角色。然而&#xff0c;随着市场竞争的日益激烈&#xff0c;货代企业面临着越来越多的挑战&#xff1a;客户需求多样化、业务流程复杂化、运营成本上升、利润空间压缩……这些挑战迫使货代企业不断寻求创新和突破…

Lyra学习笔记2 GFA_AddComponents与ULyraPlayerSpawningManagerComponent

目录 前言GameFeatureAction_AddComponentsULyraPlayerSpawningManagerComponent缓存所有PlayerStart位置选择位置 前言 1.以control模式为例 2.比较散&#xff0c;想单独拿出一篇梳理下Experience的流程 GameFeatureAction_AddComponents 这部分建议看 《InsideUE5》GameFeatu…