- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
Redis 的持久化功能是区别于 Memcached 显著特性,数据持久化可以保证系统在发生宕机和重启后数据不会丢失,对于 redis 这种存储在内存中的数据库显得尤为重要。 在 Redis 4.0 以前数据持久化的方式主要有两种
RDB 是将内存中的数据在某一时刻的状态记录下来以二进制的方式存储到磁盘中,通过生成一个经过压缩的二进制文件来实现数据库状态的复原。默认是 dump.rdb 文件,它的优点是以二进制存储,占用空间更小,数据存储更紧凑。
因为 RDB 文件是保存在磁盘中,哪怕 Redis 服务器宕机,Redis 服务器就可以通过该文件来还原数据库状态。
触发RDB持久化既可以通过手动执行,也可以根据服务器配置选项定期执行。主要分为手动触发和自动触发两种方式。
手动触发主要是通过save 和 bgsave 两个命令来生成RDB 文件
自动触发主要是通过 redis.conf 配置文件来完成:
# save <seconds> <changes> 周期性执行RDB持久化条件的设置格式
# 默认配置
save 900 1
save 300 10
save 60 10000
# 文件名称
dbfilename dump.rdb
# 文件保存路径
dir /home/work/app/redis/data/
# 如果持久化出错,主进程是否停止写入
stop-writes-on-bgsave-error yes
# 是否压缩
rdbcompression yes
# 导入时是否检查,这里是使用CRC64算法来进行数据校验,会增加性能消耗
rdbchecksum yes
还有其他情况也可能会导致自动触发:
数据量较大时进行快照,用时相对会比较长。如果服务器在这个期间收到写请求,那么就不能保证快照的完整性。那么Redis 是如何做的?
Redis 使用的是操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。
如下图,针对 bgsave 命令触发 RDB 机制来说,如果主线程要修改一块数据(图中的键值对 C),这块数据就会被复制一份,生成该数据的副本(键值对C')。此时中线程在该副本上进行修改,bgsave 子线程继续把原来的数据(键值对 C)写入 RDB 文件中。
这样既保证了RDB 文件的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
数据没有全部写入磁盘前,该次快照操作都是失败的。将以这次快照操作前的完整 RDB 快照文件作为恢复内存的数据。也就是此次快照操作过程不能影响上一次的备份数据。实际上在操作时 Redis 服务会在磁盘上创建一个临时文件来进行数据操作,待操作成功后才会用这个临时文件替换上一次的备份数据。
频繁的执行全量快照,能够带来更快的恢复速度。但同时也会带来大量的开销,给磁盘带来压力,多个快照竞争有限的磁盘带宽,容易造成恶性循环。此外, bgsave 子进程需要通过 fork 操作从主线程创建出来。如果频繁的fork 出 bgsave 子进程就会阻塞主线程。因此 Redis 在有一个 bgsave 运行时,就不会再启动第二个 bgsave 子进程。
这里就可以采用增量快照的方法,就是在全量快照后,后续的快照只对修改后的数据进行快照,避免对数据重复的那部分进行快照带来的消耗,这样更加高效。这里就需要对修改的文件数据进行记录,如下图所示:
但是,我们在增量快照时,记录所修改的数据信息也是一部分的开销,在大量数据修改时的记录数据,其内存开销也不少。所以对于做快照的频率,不能太高也不能太低。那么有什么解决方法既能够让 RDB 快速恢复,又能以较小的开销实现少丢数据呢?
Redis 4.0 提出了 混合使用 AOF 日志和内存快照的方法可以很好的解决上面的场景。
AOF (Append Only File)日志和大多数的数据库写入日志的方式不同,采用的是写后日志。(比如 MySQL 是通过写前日志(Write Ahead Log, WAL)和两阶段提交来实现数据和逻辑的一致性)
写后日志的意思是 Redis 先将数据写入内存,然后再记录日志,如下图:
采用后写日志有这样的好处:
但是在写回磁盘时也会产生风险:
这两个风险是 AOF 写回磁盘时机不当造成的,对于这两个风险,AOF 有三种写回策略可以避免。也就是在文件写入同步时发生。
AOF 持久化功能的实现可以分为命令追加(append)、文件写入(write)和文件同步(sync)三个步骤。
当 AOF 持久化功能处于打开状态时,服务器在执行完一个写命令之后,就会以协议格式将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾中,这个 aof_buf 是以 sds 对象形式存储。
struct redisServer {
...
// AOF 缓冲区
sds aof_buf;
...
};
以Redis 服务端收到 set testkey testvalue
命令后的记录为例,查看 AOF 日志的运行原理。
在服务器执行 set 命令后,会将以下协议内容追加到 aof_buf 缓冲区的末尾:
*3\r\n$3\r\nSET\r\n$7\r\ntestkey\r\n$9\r\ntestvalue\r\n
*3
:表示当前命令有三个部分,每个部分都是由$+数字
开头,后面紧跟具体的命令、键或值\r\n
:是换行符,具体如上图所示$+数字
:数字表示这部分的命令、键或值一共有多少个字节,比如 $3 set
表示这部分有三个字节的命令,也就是 set
命令Redis 的服务器进程就是一个事件循环(loop),在处理文件事件时可能会执行写命令,所以在服务器每次结束一个事件循环之前,它会调用 flushAppendOnlyFile
函数,考虑是否需要将 aof_buf 缓冲区中的内容写入到AOF 文件中去。
def eventLoop():
while True:
//处理文件事件,接收命令请求以及发送命令回复
//处理命令请求时可能会有新内容被追加到 aof_buf缓冲区中
processFileEvents();
//处理时间事件
processTimeEvents();
//考虑是否要将 aof_buf中的内容写入和保存到 AOF文件里面
flushAppendOnlyFile();
而flushAppendOnlyFile
函数的行为有服务器配置的 appendfsync 选项的值来决定。其值主要有三种:
在保存了 AOF 文件后,服务器只需要重新执行 AOF 文件中的写命令后,就可以还原服务器关闭之前的数据库状态,其具体步骤如下:
因为 AOF 是通过保存被执行的写命令来完成 Redis 持久化的,所以随着 Redis 的运行时间越长,AOF 文件中存储的日志内容会越来越多。会给 Redis 服务器,带来很大的影响。因此 Redis 提供了 AOF 文件重写功能解决这一痛点。
重写机制具有“多变一”的功能,也就是对旧日志文件中的多条命令,在重写后的新日志变成了一条命令。如下图所示:
AOF 重写过程是由后台子进程 bgrewriteaof 来完成,重写过程是一个拷贝,两处日志:
一个拷贝:是指每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,fork 会把主线程的内存拷贝一份给 bgrewriteaof。所以这个子线程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。
两处日志:
第一处日志指的是正在使用的 AOF 日志,Redis 会把这个操作写到它的缓冲区。即使宕机了,这个 AOF 日志的操作仍然是齐全的可以用于恢复。
第二处日志指的是新 AOF 重写日志,这个操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作
所以说在每次 AOF 重写时,Redis 会先执行一份内存拷贝,用于重写;然后使用两个日志保证在重写过程中新写入的数据不会丢失。同时因为 bgrewriteaof 子进程的出现,这个过程并不会阻塞主线程。
有两个配置项可以控制 AOF 重写的触发:
auto-aof-rewrite-min-size
: 表示运行 AOF 重写时文件的最小大小,默认是 64MBauto-aof-rewrite-percentage
: 这个值是当前 aof 文件和上一次重写后 aof 文件差值,再除以上一次重写 aof 文件大小。在介绍 RDB 机制时,我们了解到是否有一种方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据?也就是混合使用 RDB 和 AOF 两种机制的方法:就是让 RDB 快照以一定频率执行,在两次快照之间使用 AOF 日志记录这期间的所有命令操作。
如上图所示,第一次全量快照后,在T1 和 T2 时刻修改用 AOF 日志记录,等到第二次全量快照时,可以清空 AOF 日志。因为此时的修改都已经记录到快照中,恢复时也就不再使用日志了。
所以 RDB 和 AOF 混合机制综合了上述两种机制的优缺点。
AOF 的载入和还原过程在 AOF 小节中有提到。现在谈谈同时存在两者的情况,服务器如何用哪个文件来还原数据库状态:
《redis 设计与实现》
https://baijiahao.baidu.com/s?id=1654694618189745916&wfr=spider&for=pc
基本上我的情况是这样的: 1) 我最初在没有 AOF 的情况下启动了 Redis,并让它运行了 n 周。 2) 我决定要使用 AOF,所以我在 n+1 周后重启 Redis 并打开 AOF。 3) 我
AOF(Append Only File) 以日志的形式来记录每个写操作(增量保存) ,将 Redis 执行过的所有写指令记录下来 (读操作不记录), 只许追加文件但不可以改写文件 ,
一、AOF1、AOF 是什么以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,
我正在寻找备份Redis数据的最佳方法。 我读了有关RDB和AOF的文章。但是从我的 Angular 来看,最好的方法是按以下方式进行组合: 定期创建RDB,然后仅保存AOF。 这样,当您重新启动时。
我最近将 Redis 配置为使用 AOF 以及 RDB 快照。 但是,看起来 AOF 在服务器启动时没有正确重放。 我停止了服务。然后我使用 redis-check-aof 确保 /var/redis
今天为大家介绍Redis的另一种持久化策略——AOF。 什么是AOF 男孩“一觉醒来”忘记了对女孩子的承诺,这时候女孩子把曾经海誓山盟的录音逐条播放给男孩子听,帮助他“恢复记忆”。 “男孩
我的 Redis 实例显然已停止重写 AOF 文件(它已增长到许多 Gb)。更糟糕的是,它似乎停止为新的客户端连接提供服务(当使用 redis-cli 连接时,连接会通过,但随后它会在任何命令上卡住)
我已阅读 Redis 文档以找到标题的答案。但我找不到它。我想知道在集群节点迁移时如何操作RDB和AOF。 假设在同一个集群中有2个节点。(A节点,B节点)* RDB、AOF选项开启。 如果A的一些数
我正在使用 Redis 2.8.4。仅在配置中启用附加。根据我的要求,它工作正常,但这个文件可能会变得越来越大,因此将来可能会造成内存不足?有什么解决办法吗? 最佳答案 Redis 有一种方法可以通过
本文已经收录进 JavaGuide (「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。) Redis 持久化机制属于后端面试超高频的面试知识点,老
一、Redis 持久化简介 Redis 的持久化功能是区别于 Memcached 显著特性,数据持久化可以保证系统在发生宕机和重启后数据不会丢失,对于 redis 这种存储在内存中的数据库显得尤为重要
我正在尝试在具有以下配置的 Redis 中使用混合持久性(RDB + AOF 作为尾部): aof-use-rdb-preamble yes appendonly yes save 10 1 # 或
是否有一个配置选项可以防止 Redis 在“变得太大”时重写 AOF 日志? 最佳答案 来自 redis.conf : # Specify a percentage of zero in order
我们在生产中使用 6 GB 数据大小的 redis 服务器,最初我们认为 Redis 只能用作内存缓存,如果它重新启动,那么我们可以从持久性数据存储中重新填充,停机时间最短。 现在我们意识到从持久性存
背景 昨天我们的机器意外崩溃,Redis 的 AOF 文件损坏了。 尝试使用 sudo systemctl start redis-server 启动服务时我们收到以下日志: Bad file for
如何彻底禁用RDB和AOF?我不关心持久性,只希望它在内存中。 我已经注释掉了: #save 900 1 #save 300 10 #save 60 10000 但这没有帮助,我看到 Redis 仍在
有没有办法将 AOF 文件保存在 Amazon S3 上而不是存储在本地? 这将避免用完大型数据集的磁盘空间。 最佳答案 您可以将 S3 挂载为盘符(例如:TntDrive)并设置 Redis 写入该
我正在读这个article关于 Tarantool,他们似乎说 AOF 和 WAL 日志的工作方式不同。 Tarantool: besides snapshots, it has a full-sca
如何在 Windows 上的 Redis 中启用 AOF? 我想将数据写入磁盘,以便在服务器重新启动后再次使用它。 在我试过的 .php 文件中: $redis->bgRewriteAOF(); 在r
对 Redis 有点陌生。 假设设置/情况:假设 Redis 每 10 分钟做一次快照。 AOF 关闭。你有一个名为“帖子”的集合,它保存帖子的 ID。您还有 MySQL 表来保存帖子的 ID。 My
我是一名优秀的程序员,十分优秀!