(七)Redis 持久化 AOF、RDB
Redis 一旦服务器宕机,内存中的数据将全部丢失,从后端数据库恢复这些数据,对数据库压力很大,且性能肯定比不上从 Redis 中读取,会拖慢应用程序。所以,对 Redis 来说,实现数据的 持久化 ,避免从后端数据库中进行恢复,是至关重要的。
1、AOF 日志
AOF 日志是先执行命令,把数据写入内存,然后才记录日志以文本形式保存,如下图:"*3" 表示命令有三个部分组成,每部分由"$+数字"开头,"$3 set"表示这部分有三个字节,指"set"命令,"$7 testkey"表示该部分有七个字节,即"testkey"命令,以此类推。
AOF 写后日志只有命令能执行成功,才会被记录到日志中,避免额外的检查开销,也避免了出现记录错误命令的情况,而且不会阻塞当前的写操作。说完 优点 说 风险 ,如果刚执行完命令还没有来得及记日志就宕机了,就有丢失的风险。其次,AOF 日志在主线程中执行,如果在把日志文件写入磁盘压力过大,可能会带来阻塞风险。
AOF 风险与写回磁盘有关,针对这个问题提供了三种 写回策略 ,即配置项 appendfsync 的三个可选值:
(1)Always 同步写回:每个写命令执行完,立马同步地将日志写回磁盘
(2)Everysec 每秒写回:每个写命令执行完,先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘
(3)No 操作系统控制的写回:每个写命令执行完,先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
三种策略各有优劣,汇总如下:

选定写回策略,并非万事大吉,随着接收的写命令越来越多,AOF 文件会越来越大,带来性能问题。主要是以下三个方面:
(1)文件系统本身对文件大小有限制,无法保存过大的文件
(2)如果文件太大,之后再往里面追加命令记录的话,效率也会变低
(3)如果发生宕机,AOF 中记录的命令要一个个被重新执行,文件太大导致整个恢复过程就会非常缓慢,影响 Redis 正常使用
日志文件太大了怎么办呢?这个时候,AOF 重写机制 就登场了。当一个键值对被多条写命令反复修改时,AOF 文件会记录相应的多条命令,而重写时,只会根据这个键值对当前的最新状态,为它生成对应的写入命令,这样一来,一个键值对在重写日志中只用一条命令就行了,并且在日志恢复时,只用执行这条命令,就可以直接完成这个键值对的写入了。举个栗子:
AOF 重写并不会阻塞主线程,重写过程是由后台线程 bgrewriteaof 来完成的,通过内存拷贝和两处日志保证数据的完整性。

2、RDB 内存快照
内存快照 RDB 就是 Redis DataBase 的缩写,和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。但同时也面临两个问题:
(1)对哪些数据做快照?这关系到快照的执行效率问题。
(2)做快照时,数据还能被增删改吗?这关系到 Redis 是否被阻塞,能否同时正常处理请求。
为了提供所有数据的可靠性保证,全量快照会把内存中的所有数据都记录到磁盘中,一个都不少。这样会花费很多时间,全量数据越多,RDB 文件就越大,往磁盘上写数据的时间开销就越大。对于 Redis 而言,它的单线程模型就决定了,我们要尽量避免所有会阻塞主线程的操作。Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave:
(1)save:在主线程中执行,会导致阻塞。
(2)bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
bgsave 避免主线程阻塞,可以正常接收请求,但是,为了保证快照完整性,它只能处理读操作,不能修改正在执行快照的数据。Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。示意如图:
简单来说,主线程 fork 生成 bgsave 子进程,可共享主线程的所有内存数据。bgsave 子进程运行读取主线程的内存数据,并把它们写入 RDB 文件。此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),则主线程和子进程互不影响。如果主线程要修改数据(例如图中的键值对 C),则会生成该数据的副本,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。
至此上面提的两个问题“哪些数据做快照”、“做快照时数据能否修改”就都解决了。新的问题又产生了,快照间隔多久做一次合适?如果在第二次快照前宕机,就可能出现数据丢失的问题,如果太频繁又会出现第一个还没结束,第二个又开始的情况。虽然 bgsave 执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会给磁盘带来额外的开销,并且 bgsave 子进程需要通过 fork 操作从主线程创建出来,频繁操作依然会阻塞主线程。
此时,增量快照就登场了,做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。比如 T1 和 T2 时刻如果再做快照,我们只需要将被修改的数据写入快照文件就行。
虽然我们记住哪些数据被修改了,但“记住”这个操作,需要我们使用额外的元数据信息去记录,这会带来额外的空间开销问题。有时改动较小时,又要引入的额外空间区记录,有些得不偿失。此时我们就可以混合使用 AOF 日志和内存快照的方法,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
如图,T1 和 T2 时刻的修改,用 AOF 日志记录,在第二次做全量快照时,就可以清空 AOF 日志,因为修改都已经记录到快照中了。这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势,可谓鱼和熊掌兼得。
(七)Redis 持久化 AOF、RDB的更多相关文章
- Redis 持久化之RDB和AOF
Redis 持久化之RDB和AOF Redis 有两种持久化方案,RDB (Redis DataBase)和 AOF (Append Only File).如果你想快速了解和使用RDB和AOF,可以直 ...
- 详解Redis持久化(RDB和AOF)
详解Redis持久化(RDB和AOF) 什么是Redis持久化? Redis读写速度快.性能优越是因为它将所有数据存在了内存中,然而,当Redis进程退出或重启后,所有数据就会丢失.所以我们希望Red ...
- redis持久化(RDB、AOF、混合持久化)
redis持久化(RDB.AOF.混合持久化) 1. RDB快照(snapshot) 在默认情况下, Redis 将内存数据库快照保存在名字为 dump.rdb 的二进制文件中. 你可以对 Redis ...
- Redis - 持久化 AOF 和 RDB
Redis - 持久化 AOF 和 RDB AOF AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集. AOF 文件中的命令全部以 Redis 协议的格 ...
- Redis 持久化之RDB和AOP
Redis 持久化之RDB和AOP Redis 有两种持久化方案,RDB (Redis DataBase)和 AOP (Append Only File).如果你先快速了解和使用RDB和AOP,可以直 ...
- Redis持久化——AOF日志
最新:Redis内存--内存消耗(内存都去哪了?) 最新:Redis持久化--如何选择合适的持久化方式 最新:Redis持久化--AOF日志 更多文章... 上一篇文章Redis持久化--内存快照(R ...
- 【Redis】Redis学习(七) Redis 持久化之RDB和AOF
Redis 持久化提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF. RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AOF ...
- Redis 持久化之RDB和AOF详解
一.RDB 详解 RDB 是 Redis 默认的持久化方案.在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中.即在指定目录下生成一个dump.rdb文件.Redis 重启会通过 ...
- [转载]Redis 持久化之RDB和AOF
原文链接:https://www.cnblogs.com/itdragon/p/7906481.html 温馨提示 在正式数据(当然是非生产环境啦)练习以下操作时,一定一定一定记得备份dump.rdb ...
- redis持久化AOF与RDB
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原 ...
随机推荐
- java redis api及test demo
1.CacheService.java package com.redis.demo; import com.alibaba.fastjson.JSON; import com.alibaba.fas ...
- FreeRTOS简单内核实现5 阻塞延时
0.思考与回答 0.1.思考一 为什么 FreeRTOS简单内核实现3 任务管理 文章中实现的 RTOS 内核不能看起来并行运行呢? Task1 延时 100ms 之后执行 taskYIELD() 切 ...
- FinalReference 如何使 GC 过程变得拖拖拉拉
本文基于 OpenJDK17 进行讨论,垃圾回收器为 ZGC. 提示: 为了方便大家索引,特将在上篇文章 <以 ZGC 为例,谈一谈 JVM 是如何实现 Reference 语义的> 中讨 ...
- C# .NET 常见DeepCopy 深度拷贝的性能对比
先上结论 Method Mean Error StdDev Gen0 Gen1 Allocated JSONConvert 2,273.02 ns 43.758 ns 52.091 ns 0.6599 ...
- python之基本类型
1 *********************************pyhton基本数据类型***************** 2 数字 int 3 ******************* 4 - ...
- FLUTTER 中 Isolate 的一个例子.
isolate 起因 最近看了一点isolate的东西, 自己写了一个例子. 普通的的 consummer-producer例子是只有前后两端的,实际上,会把前后两端再进行包装. 我这里这个例子,是把 ...
- Cannot add or update a child row: a foreign key constraint fails
在使用Django添加用户时出现报错: 1 django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a fo ...
- Java异步判断线程池所有任务是否执行完成的方法
1.使用ExecutorService和CountDownLatch的方法示例 在Java中,当我们使用线程池(如ExecutorService)来执行异步任务时,常常需要知道所有任务是否都已经完成. ...
- 服务之间的调用之RPC深入理解
一:RPC RPC 即远程过程调用(Remote Procedure Call Protocol,简称RPC),像调用本地服务(方法)一样调用服务器的服务(方法).通常的实现有 XML-RPC , J ...
- 说说RabbitMQ延迟队列实现原理?
使用 RabbitMQ 和 RocketMQ 的人是幸运的,因为这两个 MQ 自身提供了延迟队列的实现,不像用 Kafka 的同学那么苦逼,还要自己实现延迟队列.当然,这都是题外话,今天咱们重点来聊聊 ...