《Redis核心技术与实战》学习总结(五)——Redis的数据同步机制
mhr18 2024-11-06 10:59 24 浏览 0 评论
Redis的数据同步机制
对于Redis来说,其高可用性是由两方面来保证的:
一方面是数据尽量少丢失,前一篇总结推文提到的AOF和RDB实现了。
另一方面是服务尽量少中断,Redis则是靠增加副本冗余量即同一份数据保存在多个实例上来实现的。
对于多副本模式,Redis和关系型数据库一样,提供了主从库模式来保证数据副本的一致性。主从库之间采用的是读写分离的方式,即读操作可以被主库/从库接收,但是写操作只能先被主库接收执行然后才由主库同步给从库。
那么问题来了,为啥要用读写分离实现?
因为,如果每次的修改请求都发到不同的实例上,要保证数据的一致性,就需要涉及到加锁和协商是否完成修改等操作,这会带来很大的性能开销。而如果所有的修改都只在主库上进行,就无需协调三个实例,只需要同步给从库,进而保持数据一致性。
Redis主从库同步流程详解
假设现在我们有两个实例,分别是主库实例1(172.16.19.3)和实例2(172.16.19.5),我们的目标就是让实例2成为实例1的从库,并进行数据同步。
第一次同步过程
在实战中,只需要实例2的shell中执行以下命令就可以将实例2作为实例1的从库,并从实例1上复制数据。
replicaof 172.16.19.3 6369
虽然就这一个命令真简单,而在这背后,Redis偷偷摸摸地进行了三个阶段的操作,如下图所示:
阶段1:从库向主库发送psync命令,表示进行数据同步。该命令格式如下所示:
# 命令格式:psync runID offset
# psync ? -1
# 其中?代表从库并不知道主库的runID,-1表示第一次复制
主库收到psync命令确认后,会向从库发送一个FULLERSYNC的响应命令,并带上主库的runID和目前的复制进度offset。
# 命令格式:FULLERSYNC runID offset
# FULLERSYNC代表全量复制,一般用于第一次数据同步
阶段2:主库通过发送RDB文件给从库,从库收到后在本地完成数据加载。
需要注意的点:
(1)主库会首先执行一次bgsave(bgsave不会阻塞主线程)生成RDB文件,然后才发送给从库。
(2)从库会首先清空已有的数据,然后再加载RDB数据,因为在同步之前可能保存了其他数据,不清除的话可能会数据不一致。
(3)主库在同步数据给从库中产生的写操作会用专门的replication buffer记录,然后在第三个阶段同步过去。
阶段3:主库将第二阶段执行过程收到的新的写操作命令,同步给从库。
在实现中,主库会将新收到的写操作放到replication buffer中记录下来,然后将这些操作修改发给从库,从库收到后再重新执行一遍这些操作。
以上三个阶段完成之后,主从库就算完成了一次数据同步。
为什么用RDB不用AOF?
Redis主库在向从库同步数据时使用的RDB文件,那么问题来了:
AOF记录的操作命令更全,相比RDB丢失的数据更少,为什么主库用RDB不用AOF呢?
一来RDB读取速度相对较快,从库可以快速完成RDB的读取,然后再去消费replication buffer的数据完成一次同步。而如果使用AOF,其体积大读取速度慢,且需要更大空间的replication buffer,对于一个主节点多个从节点来说的话,内存的占用就会更大;
二来AOF是Append追加模式,同时读写需要考虑并发安全问题,并且AOF是文本文件,体积较大,浪费网络带宽。
主从级联模式降低主库压力
主从库同步过程中,主库需要完成两个耗时的操作:生成RDB文件 和 传输RDB文件。现实场景中,从库一般都会有多个,如果都要和主库同步的话,会造成主库的性能压力 和 网络压力。
因为主库需要fork子进程来生成RDB文件,这个fork操作是会阻塞主线程处理正常请求的,虽然后续的bgsave过程不会阻塞主线程。
此外,传输RDB文件也会占用主库服务器的网络带宽。
Redis提供了主从级联模式,也就是所谓的“主-从-从”模式。
在主-从-从模式下,新增的从库可以设置从 集群中的某一个从库 中进行数据同步,从而避免每次都从主库进行同步,降低主库的资源消耗,保证系统的稳定性。
比如,在实际中通常会手动选择一个 内存配置较高的 从库 来作为同步源,其他新的从库加入后可以从这个从库中同步,建立主从关系。例如,下面的命令就可以实现新增从库和某一个从库建立主从关系:
replicaof 所选从库ID 6379
具体的示意图如下图所示:
全量同步后的增量同步
主从库通过FULLERSYNC进行全量复制同步 + 主从级联模式分担主库压力 之后,Redis的主从库之间就会一直维护一个长连接来进行增量的命令操作同步,这个过程又被称之为“基于长连接的命令传播”。
为何选择长连接?因为可以避免频繁建立连接的开销。
虽然长连接很方便,但也存在一个风险点:主从库网络断了 或 阻塞了。这个风险可能导致的问题就是:主从库之间数据无法保持一致,客户端可能从读库读到过时的数据。
当然,Redis早就已经为我们想好了解决方案,不过得分为两个版本来看:
Redis 2.8之前,如果出现了网络闪断,Redis主从库间会重新进行一次全量复制。当然,全量复制就意味着有很大的开销。
Redis 2.8之后,如果出现了网络闪断,Redis主从库间会采用增量复制的方式继续同步。可以看到,增量复制肯定比全量复制开销要小得多。
这里的增量复制的核心要点就在于Redis引入了repl_backlog_buffer缓冲区,现在我们就来看看这个repl_backlog_buffer到底是个啥东东。
repl_backlog_buffer是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置。下图展示了repl_backlog_buffer的示意图:
可以看到,正常情况下,主从库的偏移量基本相等。随着主库不断接收新的写操作,它在缓冲区中的写位置会逐步偏离起始位置。对主库来说,对应的偏移量就是 master_repl_offset,只要主库的新写操作越多,这个值也就越大。同理,从库在复制完写操作命令后,它在缓冲区中的读位置也开始逐步偏移起始位置。对从库来说,其对应的已复制偏移量就是 slave_repl_offset。
当网络闪断异常情况下,主库可能会接收到新的写操作命令,因此,可以看出,主库的偏移量master_repl_offset > 从库的偏移量slave_repl_offset。那么,此时就只需要把 master_repl_offset 和 slave_repl_offset 之间的命令操作同步给从库就ok了。
综上所述,增量同步的过程整体如下:
repl_backlog_buffer扩展
在增量复制过程中,需要注意的点:repl_backlog_buffer是一个环形缓冲区,在缓冲区被写满了之后,主库再次写入时就会覆盖掉之前写入的操作。
那么问题来了,如果从库读取的速度很慢,就有可能出现从库读取到了不一致的数据。
如何解决?
Redis提供了一个 repl_backlog_size 的参数,它与缓冲区的空间大小紧密相关。在实际中,一般其设置为:repl_backlog_size = 缓冲区空间大小 * 2,这样可以降低由于读库消费速度慢导致的数据不一致。
缓冲空间的计算公式是:
缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小
But,如果并发请求量特别大,两倍的缓冲区空间都不够用,主从库仍然存在不一致的风险,那么此时,可能需要根据Redis所在服务器的性能指标(主要是内存资源)再增加一些 repl_backlog_size 值。
End总结
本文总结了Redis主从库读写分离模式数据同步的总体机制 及 基本流程,了解了全量同步 和 增量同步的过程,涉及了 主从级联模式 和 repl_backlog_buffer缓冲区。
参考资料
极客时间,蒋德钧《Redis核心技术与实战》
黄建宏,《Redis设计与实现》
拉钩教育,刘海丰《架构设计面试精讲》
作者:Edison Zhou
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 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)