面试官:聊聊Redis如何用主从复制模式 实现高可用
mhr18 2024-11-07 11:04 22 浏览 0 评论
作者:绘你一世倾城 链接:https://juejin.im/post/5e755f0d518825490e458453
之前总结过redis的持久化机制:深度剖析Redis持久化机制,持久化机制主要解决redis数据单机备份问题;redis的高可用需要考虑数据的多机备份,多机备份通过主从复制来实现,这是redis高可用的基石。本文将详细介绍redis主从复制的实现原理,在使用过程中应该注意的问题和相关配置。
1. CAP理论
CAP理论是分布式领域的牛顿定律,所有的分布式存储中间件都要使用它作为理论基石。如下图所示:
这个原理很简单,首先明确几个概念:
- C : Consistent, 一致性
- A : Availability, 可用性
- P : Partition tolerance, 分区容忍性
分布式系统的节点往往分布在不同的机器上,它们之间由网络进行隔离,当网络断开时就会产生网络分区。网络分区不可避免,但是当网络分区发生时,对分布式系统中一个节点的修改操作无法同步给其它节点,数据一致性也就无法满足;想要满足一致性,除非牺牲可用性,也就是暂停分布式节点服务,等到网络恢复,数据一致后,再对外提供服务。分布式系统中网络分区不可避免,一致性和可用性水火不容。这就是cap理论:网络分区发生时,一致性和可用性两难全。
2.redis主从复制
2.1 概述
互联网圈经常谈“三高”架构:高并发、高性能、高可用。对于redis来说,高并发、高性能可以保证,高可用需要架构的设计,单机redis由于存在系统崩溃、硬盘故障的风险,还有内存的限制,所以企业一般都会搭建主从,对系统有更高要求会搭建集群。
为了保持数据一致性,主节点(master)只写,从节点(slave)只读,数据由主节点复制给从节点,这个复制的过程就是主从复制。
redis的主从复制是异步的,分布式的redis系统并不满足一致性要求,但是在网络断开的情况下,主节点依然可以对外提供服务,满足可用性。redis保证最终一致性,从节点会努力追赶主节点,最终从节点的状态会和从节点保持一致。网络断开的情况下,主从节点数据会出现大量的不一致,但一旦网络恢复,从节点会继续追赶主节点,最终达到和主节点状态一致。
为了减轻redis主节点的同步负担,redis 的后续版本还增加了从从同步,与此同时,数据一致性会变差。
2.2 主从复制的作用
主从复制在服务中起到了什么效果呢?
- 读写分离:master写,slave读,提高服务器的读写负载能力。
- 负载均衡:基于主从架构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高redis服务器并发量和数据吞吐量。
- 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复。
- 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式。
- 高可用基石:基于主从复制,构建哨兵模式与集群,实现redis的高可用方案。
2.3 怎样配置实现主从复制?
有三种配置实现redis的主从:
- 方式一:客户端发送命令
slaveof <masterip> <masterport>
复制代码
- 方式二:启动服务器时添加参数
redis-server -slaveof <masterip> <masterport>
复制代码
- 方式三:服务器配置文件中配置(通过redis.conf)
slaveof <masterip> <masterport>
复制代码
比较主流的用法是通过配置文件的方式实现主从。还有其它的一些命令:
- 主从断开连接,可以从客户端发送命令
slaveof no one
复制代码
- 服务端设置了授权访问
#master有两种方式设置
//-- 1.master配置文件中设置
requirepass <password>
//-- 2.master客户端发送命令设置密码
config set requirepass <password>
config get requirepass
#slave有三种方式实现认证
//-- 1.客户端发送命令设置密码
auth <password>
//-- 2.slave配置文件设置密码
masterauth <password>
//-- 3.启动客户端设置密码
redis-cli -a <password>
复制代码
2.4 redis主从复制的工作流程
redis主从复制实现过程有三个阶段:
建立连接、数据同步、命令传播。建立连接阶段主从节点建立通信的桥梁,彼此之间同步一些基础信息;数据同步阶段实现从节点全量同步主节点的数据;从节点同步完主节点数据之后,就进入了命令传播阶段,主节点接收写请求,数据不断发生变化,通过命令传播阶段主节点将数据源源不断的同步给从节点。下边我们详细介绍主从复制这三个阶段的工作细节和注意事项。
2.4.1 建立连接阶段
建立slave到master的连接,使master能识别slave, 并保存slave的端口号;与此同时,slave也保存master的地址和端口号信息。
- slave发送slaveof ip port命令给master,master响应slave
- slave保存master的ip和端口号,建立socket连接
- 在socket连接之上,主从节点实现了心跳机制,这部分内容也比较重要,后边会提到。
- 如果有认证机制,从节点通过上边说到的认证指令,发送认证信息给master,实现认证。
- 从节点将自己的端口信息发送发送给主节点,主节点保存。
通过以上过程主从之间的连接就建立了。
2.4.2 数据同步阶段
数据同步阶段实现的功能是从节点从主节点同步全量的数据。这个过程又分为几个小阶段,最主要的就是数据的全量复制和部分复制, 对应的流程就是主节点发送rdb文件同步数据和发送缓冲区写命令(aof)同步数据给从节点。下图是实现细节:
- 首先slave节点先发起命令psync ? -1,向master节点要全量数据。
- master节点接收到指令以后,执行bgsave,将当前内存数据快照保存为rdb文件,这个过程为了不影响主节点继续对外提供服务,采用了Copy On Write技术。与此同时,master节点也会将bgsave保存快照期间接收到的写更新命令添加到复制挤压缓冲区当中。master节点rdb文件生成完毕以后,会通过第一阶段建立的socket连接将它发送给slave节点,还会发送+FULLRESYNC runid offset给slave节点,告诉slave节点自己的runid和offset。
什么是runid?
redis-server在每次启动的时候都会生成一个runid,因为redis-server是一个守护进程,所以在运行期间,runid不会发生变化,可以通过info server指令查看runid,它是一个40位字符长度的字符串。上文提到的psync有两个参数,和+FULLRESYNC一样:psync <runid> <offset>;runid的意义是什么呢?当master节点发生故障发生了变更后,在接到slave的指令以后,对比参数中的runid如果和自己的runid不一致,就会再次进行全量复制,因为换主了。
什么是复制挤压缓冲区和offset?
复制挤压缓冲区是一个先进先出(FIFO)的环形队列,用于存储服务端执行过的命令,每次传播命令,master节点都会将传播的命令记录下来,保存在这里。
复制挤压缓冲区由两部分组成:偏移量和字节值。字节值是redis指令字节的存储(redis指令以一种Redis序列化文本协议的格式存储),偏移量offset就是当前字节值在环形队列中的偏移量。
- slave节点接收完master节点同步的rdb文件之后,将rdb的内容加载到自己的内存,然后将master节点的runid和offset记录下来。
- 有了master节点的runid和offset,在加载完rdb文件之后,就开始向master节点发送新的命令psync runid offset,向master节点要新数据。新数据是master节点在bgsave生成rdb文件时和向slave同步数据的这段时间产生的,所以这段时间的工作也称为部分复制。
- master节点收到slave节点发送的请求数据命令之后,会检查runid是否一致(是否换主),offset是否一致(因为复制挤压缓冲区是定长的,所有有可能会溢出),这两个条件只要有一个不满足,master就会向slave再次全量的同步数据(读者可能会发现,如果master节点写并发很高,复制挤压缓冲区又设置的比较小的话,可能会每次向slave同步完数据以后,每次复制挤压缓冲区都会溢出,造成主从之间循环的全量复制。这确实是应该规避的问题!我们后边会针对主从复制应该考虑的问题做一个总结)。在runid和offset都满足的情况下,master节点就会向slave节点发送指令+CONTINUE offset,接着从offset位置开始同步数据,数据都在主节点的复制挤压缓冲区中了,所以直接复制发送就可以了。
- slave节点接收到master节点发送的+CONTINUE offset指令之后,更新自己保存的offset值,然后将从master节点同步过来的数据,使用bgrewriteaof,重放aof数据。
到这里,主从复制的第二阶段:数据同步阶段工作就完成了。
2.4.3 命令传播阶段
命令传播阶段类似于数据同步阶段的部分复制,当master节点数据被修改以后,就和slave节点的数据不一致了,这个时候master节点就会根据slave上报的offset开始传播数据(一主多从的架构中,master节点要记录每一个slave的offset)。slave接收到数据以后,执行bgrewriteaof重放数据。在这个工作过程中,如果因为网路问题导致offset溢出或者换主的情况,主从之间还是会进行数据的全量同步的。
2.5 心跳机制
进入命令传播阶段以后,master节点与slave节点需要进行信息传递,使用心跳机制进行维护,实现双方保持在线。
master节点心跳使用指令PING,由配置repl-ping-slave-period决定,默认10秒,作用是判断slave是否在线,可以通过info replication获取slave最后一次连接到现在的时间间隔,lag的值维护在0和1视为正常。
slave节点的心跳任务使用指令REPLCONF ACK {offset},周期是1秒,slave的心跳任务有两个作用:
- 汇报自己的offset给master,这在数据传播起到了关键性作用,因为master节点向slave节点传播数据,offset是一项非常重要的指标。
- 判断master是否在线
在心跳阶段应该注意:当slave节点多数掉线,或者延迟过高时,master节点为了保证数据的稳定性,将拒绝所有信息的同步。有如下配置:
min-slaves-to-write 2
min-slaves-max-lag 8
复制代码
上述配置含义是:当slave数量小于2个,或者所有的slave的延迟都大于等于8秒时,强制关闭master写功能,停止数据同步。
3.主从复制常见问题
上边介绍的主从复制是建立在主从节点间的网络和服务都正常的情况下,业务场景中要考虑更多的实际情况。
3.1 master重启
伴随着系统的运行,master节点的内存数据量变得很大的情况下,一旦master节点重启,runid将发生变化,会导致slave的全量复制操作。
这里有一个优化方案:在master节点内部创建master_replid变量,使用runid相同的策略生成,长度41位,发送给所有的slave节点。在master节点关闭时,执行命令shutdown save,进行RDB的数据持久化,将runid与offset保存在RDB文件中。在RDB文件中有了repl-id和repl-offset信息以后,通过指令redis-check-rdb命令可以查看这些信息。在master节点重启后,将RDB文件加载到内存中以后,也会将repl-id和repl-offset加载到内存中。通过info 指令可以查看:
master_repl_id = repl
master_repl_offset = repl-offset
复制代码
作用是:master节点重启之后会保存原来的runid,重启后恢复该值,会让所有的slave节点认为还是之前的master节点。
3.2 复制积压缓冲区太小
当复制积压缓冲区太小的时候,当master节点写并发很大,master节点和slave节点网络有抖动的时候,就会导致数据同步不及时,造成offset溢出,进而导致全量复制。这个时候,我们可以考虑修改复制积压缓冲区的大小,由配置repl-backlog-size控制。设置多大比较合适呢,这要根据master的并发量和网络情况做具体的评估。
3.3 slave执行了keys * 、hgetall等命令
前边内容我们提到slave节点每秒都会发送REPLCONF ACK指令到master节点,master节点调用复制函数relicationCron()同步数据给slave节点时,如果slave节点执行了keys *、hgetall等阻塞命令的时候,就会在很长一段时候得不到响应。这就会导致master的各种资源(输出缓冲区、带宽、连接)等被占用。master节点的CPU就会变高,slave频繁的断开连接。
解决方案是master节点通过配置:repl-timeout设置合理的超时时间(默认60s),超过改值,master节点将释放slave节点。
3.4 master节点发送ping指令频度低,网络存在丢包
master节点默认10s向slave节点发送一次ping指令,因为master节点不仅要处理大量的写任务,还可能维护着多个master,所以ping设置的不太及时。但是当ping指令在网络中存在丢包时,master节点如果设置的超时时间太短,就会导致master节点与slave节点断开连接。
解决方案有:提高master节点ping的频度,超时时间repl-time设置为ping指令时间的5~10倍。
3.5 网络信息不同步,数据发送有延迟
当主从同步中网络数据发送有延迟的时候,就会造成多个slave获取到的数据不同步,解决方案是优化master节点和slave节点的网络环境,通常是放置在一个机房部署。另外要监控master和slave节点的延迟,如果延迟过大,可以暂时屏蔽对slave节点的访问。通过下面指令设置:
slave-serve-stale-data yes | no
复制代码
开启后,slave节点仅仅能响应info、slaveof等少数命令,除非对数据一致性要求很高,否则不要轻易这样使用。
4.总结
本文主要总结了redis实现主从复制的实现细节和注意事项。redis的主从复制是实现高可用的重要基石,后边的文章将总结哨兵和集群的搭建。
小福利:
通过合法手段,获取到一些极客付费课程 ,嘘~,免费 送给小伙伴们。评论【666】我会私信发你
相关推荐
- 京东大佬问我,每天新增100w订单数据的分库分表方案
-
京东大佬问我,每天新增100w订单数据的分库分表方案嗯,用户问的是高并发订单系统的分库分表方案,每天新增100万订单。首先,我得理解需求。每天100万订单,那每秒大概是多少呢?算一下,100万除以86...
- MySQL 内存使用构成解析与优化实践
-
在为HULK平台的MySQL提供运维服务过程中,我们常常接到用户反馈:“MySQL内存使用率过高”。尤其在业务高峰期,监控中内存占用持续增长,即便数据库运行正常,仍让人怀疑是否存在异常,甚至...
- 阿里云国际站:怎样计算内存优化型需求?
-
本文由【云老大】TG@yunlaoda360撰写一、内存优化型实例的核心价值内存优化型ECS实例专为数据密集型场景设计,具有以下核心优势:高内存配比:内存与CPU比例可达1:8(如ecs.re6....
- MySQL大数据量处理常用解决方案
-
1、读写分离读写分离,将数据库的读写操作分开,比如让性能比较好的服务器去做写操作,性能一般的服务器做读操作。写入或更新操作频繁可以借助MQ,进行顺序写入或更新。2、分库分表分库分表是最常规有效的一种大...
- 1024程序员节 花了三个小时调试 集合近50种常用小工具 开源项目
-
开篇1024是程序员节了,本来我说看个开源项目花半个小时调试之前看的一个不错的开源项目,一个日常开发常常使用的工具集,结果花了我三个小时,开源作者的开源项目中缺少一些文件,我一个个在网上找的,好多坑...
- 免费全开源,功能强大的多连接数据库管理工具!-DbGate
-
DBGate是一个强大且易于使用的开源数据库管理工具,它提供了一个统一的Web界面,让你能够轻松地访问和管理多种类型的数据库。无论你是开发者、数据分析师还是DBA,DBGate都能帮助你提升工作效率...
- 使用operator部署Prometheus
-
一、介绍Operator是CoreOS公司开发,用于扩展kubernetesAPI或特定应用程序的控制器,它用来创建、配置、管理复杂的有状态应用,例如数据库,监控系统。其中Prometheus-Op...
- java学习总结
-
SpringBoot简介https://spring.io/guideshttp://www.spring4all.com/article/246http://www.spring4all.com/a...
- Swoole难上手?从EasySwoole开始
-
前言有些童鞋感觉对Swoole不从下手,也不知在什么业务上使用它,看它这么火却学不会也是挺让人捉急的一件事情。Swoole:面向生产环境的PHP异步网络通信引擎啥是异步网络通信?10年架构师领你架...
- 一款商用品质的开源商城系统(Yii2+Vue2.0+uniapp)
-
一、项目简介这是一套很成熟的开源商城系统【开店星】,之前推过一次,后台感兴趣的还不少,今天再来详细介绍一下:基于Yii2+Vue2.0+uniapp框架研发,代码质量堪称商用品质,下载安装无门槛,UI...
- Yii2中对Composer的使用
-
如何理解Composer?若使用Composer我们应该先知道这是一个什么东西,主要干什么用的,我们可以把Composer理解为PHP包的管理工具,管理我们用到的Yii2相关的插件。安装Compose...
- SpringBoot实现OA自动化办公管理系统源码+代码讲解+开发文档
-
今天发布的是由【猿来入此】的优秀学员独立做的一个基于springboot脚手架的自动化OA办公管理系统,主要实现了日常办公的考勤签到等一些办公基本操作流程的全部功能,系统分普通员工、部门经理、管理员等...
- 7层架构解密:从UI到基础设施,打造真正可扩展的系统
-
"我们系统用户量暴增后完全崩溃了!"这是多少工程师的噩梦?选择正确的数据库只是冰山一角,真正的系统扩展性是一场全栈战役。客户端层:用户体验的第一道防线当用户点击你的应用时,0.1秒...
- Win11系统下使用Django+Celery异步任务队列以及定时(周期)任务
-
首先明确一点,celery4.1+的官方文档已经详细说明,该版本之后不需要引入依赖django-celery这个库了,直接用celery本身就可以了,就在去年年初的一篇文章python3.7....
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)