Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)

文章目录

前言

在前面的系列文章中,我们已经完成了 Redis 基础入门、五大核心数据类型、C++ 客户端编程实战,掌握了 Redis 的基础使用与代码落地能力。而想要将 Redis 真正应用到生产环境、高并发分布式系统中,数据安全保障、命令原子性控制、服务高可用部署是必须攻克的三大核心难题。

本文将进入 Redis进阶核心篇章,聚焦三大生产级关键技术:

持久化机制:详解 RDB 快照、AOF 日志、混合持久化三种方案,解决 Redis 重启数据丢失问题,兼顾数据安全性与恢复效率;

事务控制:讲解 Redis 弱事务特性、MULTI/EXEC/WATCH命令实现,理解乐观锁在 Redis 中的应用;

主从复制:从单点问题切入,掌握主从架构搭建、全量 / 增量同步原理、拓扑结构优化,实现 Redis 读性能扩展与服务高可用。

本文从原理、配置、命令、实战、优缺点全方位拆解,帮你构建完整的 Redis 生产级知识体系,从容应对数据安全、服务扩容、故障容错等真实业务场景。

持久化

Redis实现持久化有两种策略:

1.RDB(属于定期备份)

2.AOF(属于实时备份)

RDB

Redis服务器默认都是有开启rdb的
RDB定期把Redis内存中的所有数据都给写入硬盘中生成一个快照--后续就可以使用这个快照来进行回滚

这里的定期备份有两种方式:(自动触发是一直生效的!)

1.手动触发

通过手动执行特定的命令(save或者bgsave)来触发快照生成

save:一般不建议用,因为redis会只进行快照生成这个任务,会阻塞redis其他客户端的命令

bgsave:通过多进程的方式进行快照生成,不会影响Redis服务器处理其他客户端的请求和命令

--save命令的话是直接在当前进程中往刚才同一个文件中写入数据

2.自动触发

a.在Redis配置文件中可以设置Redis每产生多少次修改就触发一次

修改详细步骤:打开redis.conf在里找save eg:save 300 10,这就表示如果 300 秒内,至少有 10 个 key 被修改了,就触发

(如果写成save ""的话就表明关闭自动触发这个功能)

b.redis进行主从复制时,主节点会自动生成rdb快照,然后把rdb快照文件内容传输给从节点

c.shutdown来关闭Redis时会触发(注意:暴力手段是不会触发的,比如:kill -9)

--但是要注意:生成一次rdb快照的成本是比较高的,所以不能让这个操作执行的太频繁!!!
Redis用RDB持久化生成的全量数据备份文件叫做dump.rdb

(属于是经过压缩后生成的二进制文件--虽然压缩消耗cpu,但是可以大幅降低文件的体积)

其所在的位置是redis.conf里面的dir选项决定的

可以用Redis自带的rdb文件的检查工具去检查其完整性:redis-check-rdb

在执行生成快照时:会把要生成的快照数据先保存到一个临时文件里,当这个快照生成完毕时,再删除之前的rdb文件,把新生成的临时的rdb文件名字改成刚才的dump.rdb

redis每次启动时,都会

1.尝试加载配置目录里的dump.rdb文件,把里面的快照数据恢复到内存

2.如果发现文件格式损坏,数据异常(比如网络传输啥都可能会导致文件损坏)的话,Redis可能会直接拒绝启动

--如果坏的只是文件的末尾,一般是可以启动的(但是数据会出问题),如果是中间位置坏了的话,会直接拒绝启动
注意:如果执行flushall的话,Redis触发RDB持久化时会把空的内存数据把直接的RDB文件给覆盖了的!
引申:

Linux文件系统主要分为三大部分:

1.超级块(存放一些管理信息) 2.inode区(存放inode节点) 3.block区(存放文件的数据内容)

修改完配置文件一般需要重启对应的服务器才会生效(除非是用命令的方式修改的)
RDB的优点:

Redis在重启时,RDB恢复数据的速度快于AOF的原因:

因为RDB使用的是二进制的方式组织数据,在恢复数据时,直接拷贝到内存就完事了

AOF则是存的命令日志(纯文本形式的字符串),需要进行一系列的字符串的切分

相较于AOF,RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。
RDB的缺点:

RDB最大的问题就是不是实时保存数据--在两次生成快照的间隔间的数据可能会因为重启而丢失

而且老版本的redis的rdb文件放到新版本的redis中不一定能识别(AOF则出现这种情况的概率很小)

--的确需要redis版本升级的话:就需要遍历旧的redis中的所有key,然后把数据插入到新的redis服务器里

AOF

AOF 以独立日志的方式记录每次写命令(通过一些特殊符号作为分隔符),Redis 重启时会重新执行 AOF 文件中的命令,以此达到恢复数据的目的。

AOF这样让工作线程先把数据写入内存中的缓冲区,积累多了后再统一写入硬盘

--大大降低了写硬盘的次数(写硬盘的效率跟写入硬盘数据的多少一般没有多大关系,但是跟写入硬盘的次数的关系很大)

而且AOF每次把新的操作写入到原有文件的末尾,属于顺序写入

(硬盘上读写数据如果是顺序读写的会比随机访问快很多)

关于上面的rewrite,是AOF的重写机制:

redis里面有个机制能针对AOF文件进行内容的整理,删除里面冗余的操作+合并一些操作,来让AOF文件变小

AOF 的主要作用是解决了数据持久化的实时性问题,目前已经是 Redis 持久化的主流方式

但是,缓冲区没来的及写入硬盘的数据丢失的风险也是很大的

--刷盘频率的调整要去redis.conf里面取搞:

里面的appendfsync选项always(每写一条命令就立刻刷盘) everysec(每秒刷一次盘) no(不主动刷盘)
AOF默认一般是关闭的,需要把redis.conf里面那个修改成appendonly yes才行

AOF开启后,RD就不生效了--redis重新启动时就是读取AOF文件(默认叫appendonly.aof)中的内容来恢复数据了
关于AOF重写机制的详细流程:

重写时,子进程只需要把内存中当前的数据取出来以AOF的格式写入到一个新的AOF文件中--不用关心原来AOF文件里有啥

创建子进程的一瞬间,子进程就继承了当前父进程的内存状态--父进程fork之后收到的数据,会搞两份,aof_buf是刷新到旧AOF文件里面的,aof_rewrite_buf是等子进程写完后刷到新AOF文件里的,这时再用新的AOF替换旧的AOF

--aof_buf时完全有必要的!因为重写到一半如果服务器挂了,重写就终止了,到头来还是要用旧AOF文件

AOF的重写过程可以手动触发或者自动触发:

手动触发:用bgrewriteaof命令

--如果当前redis已经在进行AOF的重写了的话--此时就会直接返回

--如果当前redis正在生成RDB文件快照的话--会等RDB快照生成完毕之后再进行AOF重写

自动触发:看redis.conf配置文件里的auto-aof-rewrite-min-size(触发重写时AOF的最小文件大小)和auto-aof-rewrite-percentage(当前AOF占用大小相较上次重写时增加的比例)

混合持久化

开启混合持久化:需要在redis.confaof-use-rdb-preamble yes

混合持久化的运作:

按照AOF的方式将每个操作都记录进文件,在触发AOF重写之后,就会把当前内存的状态按照RDB的二进制格式写入到新的AOF文件中;后续再进程操作的话,仍然是按照AOF文本的方式追加到文件的后面


如果Redis上同时存在AOF文件和RDB快照的话--此时以AOF为主(因为AOF中包含的数据比RDB的更全)

事务

如果Redis按照集群模式部署的话,是不支持事务的!

Redis事务这里任何能实现的效果,都能通过lua脚本进行替代!
Redis事务的特性:

弱原子性:把多个操作打包在一起,要么全都执行,要么全都不执行(不存在有一个执行失败就回滚)

不具备一致性 不具备持久性 不涉及隔离性(因为是单线程模型,所有的请求都是串行执行的)

--Redis事务其实就是为了打包命令一次性执行,防止别人插队
Redis中的事务是通过队列进行实现的:(每个客户端一个队列)

开启事务时,此时客户端输入的命令就会进入服务器的这个队列中;当遇到执行事务的命令时,就会把队列中的这些任务都按照顺序依次执行
Redis中有关事务的命令:

1.开启事务:multi

2.执行事务:exec(执行完事务之后这个事务就关闭了)

3.放弃当前事务:discard --如果事务途中服务器关闭了,就相当于discard

4.watch key(事务才用的到这个--在开启事务前执行监控):如果key被其他客户端修改了的话,事务里所有操作都会失效,exec时返回nil(非这个key的也会,这个事务完全不含key操作时也会)

--watch是通过观察key的版本号来判断key是否被修改了的!

--watchexec或者discard之后会自动结束

5.unwatch:取消这个客户端的所有的监控
引申:Redis命令里面没有能进行条件判定的,但是支持lua脚本,可以用这个来进行条件判定
引申:关于乐观锁和悲观锁

乐观锁:预期接下来锁冲突的概率很低--比如这里的watch

悲观锁:预期接下来锁冲突的概率很高

主从复制

单点问题:如果某个服务器程序只有一个节点(也就是说只有一个物理服务器),就会有1.可用性问题 2.性能/支持的并发量比较有限

所以就需要引入分布式系统去解决这个单点问题
在分布式系统中,希望使用多个服务器来部署redis,存在以下几种redis的部署方式:

1.主从模式 2.主从+哨兵模式 3.集群模式
主从模式:就是有一个主节点和若干个从节点

在主节点中保存了一堆数据,从节点会主动建立连接发起复制请求,然后主节点收到请求后生成快照把快照发给从节点

注意:从节点上的数据不允许修改,只允许读取!(客户端进行读取操作都是从从节点那读取的)

如果挂掉某个从节点,没啥影响 但是如果挂掉的是主节点,如果不处理的话,影响就很大了

真正的分布式:主节点和不同从节点要跑在不同的服务器上才对,但是下面进行模拟的话就用一个服务器启动多个不同端口的redis-server来凑合下就行了

主从模式主要是针对读操作进行的并发量和可用性的提高
在一个服务器上怎么模拟主从模式:(有三种方法)

1.在从节点的配置文件里面认大哥(eg:slaveof 127.0.0.1 6379),然后启动多个不同端口的redis-server就行了

2.在redis-server启动时加入--slaveof 127.0.0.1 6379

3.启动后运行命令:slaveof 127.0.0.1 6379

--注意:这三个redis服务器的工作目录要区分开(修改配置文件中的dir选项),不然用service redis-server start方式启动时,aof文件的权限不够 只能用redis-server 以及他们的aof文件会混写在一起

修改这个工作目录的方法:先把之前的服务器停止,然后删除之前工作目录下的aof文件或者修改aof文件所属的用户,再重新指定工作目录即可

从节点解除主从同步:slave no one--但是里面已经同步了的数据还是在的
主节点和从节点是怎么保持联系的?

netstat -anp来看就知道了--从节点是在底层相当于客户端主动向主节点发起TCP连接

Redis中执行info replication可以看到主节点和从节点是怎么传输数据的:

通过看主节点和从节点的offset就能知道他俩的数据是否一致了

(主节点的offset的维护:把命令的字节数累加到offset里)

还有个是repl_backlog_active(积压缓冲区),用处就是实现部分同步:主节点会把最近发生的数据修改不仅发给从节点,还会往积压缓冲区里发一份,来让从节点重连后可以部分同步

主从同步时分为全量同步和增量同步:

全量同步就是在从节点第一次连接主节点时发生的,增量同步就是通过那个积压缓冲区实现的
关于积压缓冲区:就是内存中的一个简单的环形队列--记录最近一段时间修改的数据(但是它的总量有限,如果存不下了就会把之前的旧数据给删掉)
把主节点AOF持久化关掉,让从节点来进行AOF备份虽然能让主节点压力变小,但是会有一个非常严重的问题:

主节点挂了之后自动重启的话,会把主节点全空的状态同步给从节点

改进方法:当主节点挂了之后,让主节点从从节点那获取AOF的文件,然后再启动
执行slave命令时,主从节点在底层干什么:

从节点会1.保存主节点信息(保存主节点的ip和端口)

2.主从建立连接(TCP--这样来验证通信双方是否能正确读写数据)

3.发送ping命令(验证主节点是否能正常工作)

4.权限验证(如果主节点设置了密码的话会有这步)

5.同步数据集(从节点会先发psync <replid> <offset>,主节点判断replication id是不是自己的,然后再同步)

6.命令持续复制

深度理解psync:

这个命令是Redis自动执行的,不需要手动操作(也就主从复制时会用到)

如果offset填-1,就是获取全量数据;填具体的正整数就是从当前偏移量位置开始获取数据

--但是并不是说从节点索要哪部分数据,主节点就一定会给哪部分数据的(不方便给部分数据的话就会给全量数据)

+FULLRESYNC表示给从节点进行全量复制 +CONTINEU:表示给从节点进行部分复制

-ERR表示Redis主节点版本过低,不支持psync命令

--如果replicationld不是自己的话,那就必须给它全量复制

--如果offset超出积压缓冲区的范围的话,也必须给它全量复制才行

全量复制的流程:

(1)从节点发送 psync 命令给主节点进行数据同步,由于是第一次进行复制,从节点没有主节点的运行 ID 和复制偏移量,所以发送 psync ? -1。

(2)主节点根据命令,解析出要进行全量复制,回复 +FULLRESYNC 响应。

(3)从节点接收主节点的运行信息进行保存。

(4)主节点执行 bgsave 进行 RDB 文件的持久化(需要重新生成!不能用原来的RDB文件)

(5)主节点发送 RDB 文件给从节点,从节点保存 RDB 数据到本地硬盘。

(6)主节点将从生成 RDB 到接收完成期间执行的写命令,写入缓冲区中,等从节点保存完 RDB 文件后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照 rdb 的二进制格式追加写入到收到的 rdb 文件中。保持主从一致性。

(7)从节点清空自身原有旧数据。

(8)从节点加载 RDB 文件得到与主节点一致的数据。

(9)如果从节点加载 RDB 完成之后,并且开启了 AOF 持久化功能,它会进行 bgrewrite 操作,得到最近的 AOF 文件。

引申:主节点进行全量复制时,可以支持无硬盘模式(主节点生成的rdb二进制数据不直接保存到文件中,而是直接进行网络传输)

--这样就省了主节点一系列的读写硬盘操作,从节点就省了写入硬盘然后再加载的过程了
什么时候会进行全量复制:

1.首次和主节点进行数据同步 2.主节点不方便进行部分复制的时候

什么时候进行部分复制:

1.从节点已经从主节点上复制过数据了,因为网络抖动或从节点重启了时会先看看能不呢进行部分复制

什么时候进行实时复制:

主节点和从节点已经同步好数据+建立TCP长连接之后的同步操作
关于实时复制:

主从节点之间建立好TCP长连接之后,主节点会把自己收到的修改数据的请求通过这个连接发给从节点,从节点也会依据这个请求去修改内存中的数据

--这个传递过程导致的延时时间的话跟层级有关

在实时复制时,检验连接是不是一直处于可用状态--心跳包机制

主节点会每隔10s给从节点发送一个ping命令,从节点收到就返回pong--超过60s都没有收到的话就会认为连接断了

从节点每隔1s就会给主节点发送一个请求来上报当前从节点复制数据的进度

--注意:这些具体时间60s 10s 1s都是可以在配置文件中修改的
关于replication id:

是主节点启动时或者从节点晋升成主节点时生成的(即便是同一个主节点,每次重启生成的replication id都是不同的)

关于info replication里面还有个master_replid2:

从节点晋升成主节点时,会把自己的以前的主节点的replid记到这里面--后续想回去的话可以手动干预+replid2来回去

关于runidreplid:

这俩不是一个东西!runid是Redis进程的id,在哨兵那才有用到(看进程是不是挂了)
两种主从结构:

  1. 扁平化结构

这个结构的话:每同步一条数据,主节点需要挨个传输给从节点--就对网卡带宽的要求特别高

2.树状拓扑结构

这个结构的话:进行数据修改时,同步的延时比第一个结构要长
引申:

如果使用service redis-server start启动的话,必须用service redis-server stop来停止

--用kill -9去停止的话,这个进程被杀死后会自动重启

--因为会有另一个进程专门去监控指定的服务器进行的运行状态
引申:

TCP内部支持nagle算法(默认是开启的)(就是针对小的tcp数据包进行合并来减少包的个数);开启了就会增加tcp的传输延迟,节省了网络带宽;关闭了就会减少tcp的传输延迟,增加了网络带宽

主从同步中关闭tcp的nagle算法的步骤:repl-disable-tcp-nodelay

相关推荐
三8441 小时前
SSRF 打内网 Redis:gopher 原理与实操
redis·web安全·bootstrap·ssrf
丁丁点灯o1 小时前
Oracle中使用外键的场景及不适用外键的情况
数据库·oracle
编程的一拳超人1 小时前
DeepSeek Harness Linux/macOS/Windows 本地下载、启动与模型配置指南
linux·windows·macos·deepseek
天天进步20151 小时前
Pixelle-Video 源码解析 #18:声音克隆功能:参考音频如何影响解说效果?
数据库·音视频
youm20031 小时前
认识Redis
redis·笔记·学习
时凌云.1 小时前
【2026最新】JDK 下载安装与环境配置全教程(Windows/Mac/Linux 三平台,零基础友好)
java·linux·macos
不懂的浪漫2 小时前
ToDesk 连接 Linux 后分辨率过低的解决方法
linux·运维·数据库
布莱克6052 小时前
Redis 详解:从核心数据结构到高可用架构
数据库
广州灵眸科技有限公司3 小时前
从手动三步到上电即连:4G模组systemd开机自连方案
linux·运维·服务器·开发语言·网络·人工智能·php