Redis虽然是一个内存级别的缓存程序,也就是redis是使用内存进行数据的缓存的,但是其可以将内存的数据按照一定的策略保存到硬盘中,这样的话就可以实现持久保存的目的;目前的话redis支持的两种不同方式的数据持久化保存机制,分别是RDB和AOF,这两种方式的话很类似于MySQL数据库的dump和二进制日志的方式。
官网原话
RDB (Redis Database): RDB persistence performs point-in-time snapshots of your dataset at specified intervals
翻译:RDB (Redis 数据库) : RDB 持久性以指定的时间间隔执行数据集的时间点快照。
实现类似照片记录效果的方式,就是在指定的时间间隔内
将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot内存快照。这样一来即使故障宕机,快照文件也不会丢失,重启Redis时,将快照文件中的数据再读到内存当中,数据的可靠性也就得到了保证。这个快照文件就称为RDB文件(dump.rdb),其中,RDB就是Redis Data Base的缩写。
前面谈到在指定的时间间隔内,这个时间具体是多少呢?
可以从redis中的配置文件中看到
上述含义:
3600秒(1小时)内至少有1次修改
300秒(5分钟)内至少有100次修改
60秒(1分钟)内至少有10000次修改
满足上述任意一个条件,就会保存一份新的RDB文件,不过这是Redis7版本中的规定,Redis7之间的版本稍有不同,保存频率要高一些
翻译:
默认情况下,Redis将数据集的快照保存在磁盘上,保存在一个名为dump.rdb的二进制文件中。你可以配置Redis,让它每N秒内,数据集中至少有M个更改,就保存一次数据集,或者你可以手动调用SAVE或BGSAVE命令
例如,如果至少有1000个key发生变化,这个配置会让Redis每60秒自动将数据集转储到磁盘上
RDB触发有两种模式,分别为手动触发和自动触发
案例:每隔5秒检测一次,如果在5秒内修改了两次就持久化rdb文件
如果插入k3 v3,超过5秒,不会持久化,再插入k4 v4,此时才会持久化
6. 数据恢复
将rdb备份,使用flashall删除所有数据,然后再删除rdb文件,再将备份的rdb文件还原,重启redis
此时数据并没有丢,说明使用rdb文件恢复数据成功。如果我们没有使用备份的dump.rdb文件,而是使用原有的dump.rdb文件,此时依然没有数据,因为执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的,无意义。除此之外,redis关机,也会产生dump.rdb文件
注意:当产生了有数据的rdb文件后,一定要进行备份迁移,不要让rdb备份文件所在的主机和redis所在的主机是同一台,一定要实现服务和备份分机隔离,以防生产机物理损坏后备份文件也挂了
翻译:
当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:Redis 调用 fork() ,同时拥有父进程和子进程。
子进程将数据集写入到一个临时 RDB 文件中。
当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。
如果现在有数据缓冲在redis中,此时还没达到备份自动触发的条件,但是这个数据非常重要,需要立刻备份,因此redis提供了两个命令:SAVE和BGSAVE
SAVE和BGSAVE的区别:
使用save命令,在主程序中执行会阻塞当前redis服务器,直到持久化工作完成执行save命令期间,Redis不能处理其他命令,也就相当于终止了对外提供服务的能力,丧失了缓存功能,需要完成持久化后,才能处理其他命令,在生产上这是一个非常严重的问题。save是同步保存。
使用bgsave命令,Redis会在后台异步进行快照操作,不阻塞快照同时还可以响应客户端请求,该触发方式会fork一个子进程由子进程复制持久化过程,这就允许主进程同时可以修改数据。bgsave是异步保存
还以使用lastsave命令获取最后一次成功执行快照的时间
不过该命令返回的是一个时间戳,在Linux上,可以用命令date -d @时间戳,将其转换为时间
在写入dump.rdb文件,或者进行文件迁移过程中,可能会出现文件破损等情况。
比如说set k1 v1111111111,当正在持久化rdb时,才将v11111写入,而后面的11111还没来得及写入,此时redis就宕机了,那么这个rdb文件就是破损的。如果这个rdb文件中有1w条数据,因为某一条数据时破损的,导致整rdb文件就失效了,所以我们就需要有一种方式,在一定范围内,检测并能修复破损的rdb文件,保证文件能被成功读取,并实现数据恢复
在/usr/local/bin有一个redis-check-rdb
这个命令就能修复破损的rdb文件
此时就表示修复成功,如果修复失败了,会进行报错,那么只能通过其他途径找回数据了
在某些情况下,可能需要禁止rdb,比如数据量太大,每次后台进行rdb时,需要fork出子进程,此时占用时间太长,导致严重IO,或者不适合当前业务
动态所有停止RDB保存规则的方法: redis-cli config set save,在本次redis活跃期间生效,redis重启后失效
改配置文件:
stop-writes-on-bgsave-error
默认yes
如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制这种不一致,那么在快照写入失败时,也能确保redis继续接受新的写请求。个人建议默认就行,因为数据一致性很重要
rdbcompression
默认yes
对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩
如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能。现在CPU、内存等硬件资源都不是瓶颈,使用默认即可
默认yes
在存储快照后,还可以i让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。默认即可
rdb-del-sync-files
在没有持久性的情况下删除复制中使用的RDB文件启用。默认情况下no,此选项是禁用的。
第一步,清空数据,并删除rdb文件
第二步,在5秒内插入两条数据,并查看rdb文件
第三步,再次插入一条数据,查看rdb文件,此时这条数据并没有持久化到rdb文件中,因为不满足5秒内写入两次
第四步,使用pgrep查看redis-server的pid,并用kill -9杀死redis-server,模拟redis-server意外宕机
第五步,重启redis,登录,查看数据是否丢失
优点:
小总结:
缺点:
小总结:
官方原话:
AOF (Append Only File): AOF persistence logs every write operation received by the server. These operations can then be replayed again at server startup, reconstructing the original dataset. Commands are logged using the same format as the Redis protocol itself.
翻译:
AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存
简单来说:
就是以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
默认情况下,redis是没有开启AOF的,开启AOF功能需要设置配置:appendonly yes
不是有了rdb持久化了吗?为什么还要引入aof,看看官方文档怎么说:
大致意思:快照不是很持久。如果运行Redis的计算机停止了,电源线故障了,或者你不小心使用kill -9杀死了Redis实例,最新写入Redis的数据将丢失。虽然对于某些应用程序来说这可能不是什么大问题,但有些用例需要完全的持久性,在这些情况下,单独使用Redis快照并不是一个可行的选择。
除此之外aof保存的是appendonly.aof文件
always
同步写回,每个写命令执行完立刻同步地将日志写回磁盘
everysec
每秒写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔1秒把缓冲区中的内容写入磁盘。该策略是redis的默认写回策略
no
操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
开启aof
因为redis默认是用rdb进行持久化的,因此要使用aof是需要在配置文件中打开的
设置aof保存路径
对于redis6,AOF保存文件的位置和RDB保存文件的位置一样,都是通过redis.conf配置文件的dir配置。比如:
对于redis7
把对应的dir该一下:dir /myredis
设置aof保存名称
redis6,aof文件只有一个,而redis7使用了Multi Part AOF的设计,aof文件从1个变为了3个
登录redis,插入两条数据,查看是否有对应的rdb文件和aof文件产生
重启redis,查看数据是否恢复成功,在此之前,有两个疑问?
aof和rdb都能恢复数据,aof和rdb是否能同时存在?
数据是由aof恢复还是由rdb恢复
备份整个appendonlydir
清空缓冲,退出redis,删除rdb文件,重启redis,查看是否恢复数据
这里数据时空的,因为前面使用了flushall命令,它也是写操作命令,也会追加到对应的aof文件中,即使数据恢复后,最终也会使用flushall清除所有缓存数据
退出redis,删除对应的aof文件和rdb文件,将备份的aof文件还原,再重新启动redis,查看数据是否恢复
可以看到,数据恢复成功
对应的写操作会放在aof的哪个文件中?验证一下
结果是放在了incr.aof文件中。
那读取操作会写入吗?验证一下
答案是并不会
如果aof每一秒写入一次,在高并发场景下,aof才写入一小半,并没有写入完整,突然redis宕机,导致aof文件错误,那如何修复这个aof文件呢?
appendonly.aof.1.incr.aof文件内部格式
如果在文件末尾随机添加数据,然后再重启redis
重启Redis之后就会进行AOF文件的载入,发现启动都不行
此时需要进行aof文件修复,使用命令:redis-check-aof --fix aof文件
随着写操作的执行,AOF变得越来越大,因此redis提供了一种瘦身计划,那就是AOF重写机制。
由于AOF持久化是Redis不断将写命令记录到AOF文件中,随着Redis不断的进行,AOF的文件会越来越大,文件越大,占用服务器内存越大以及AOF恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的峰值时,Redis就会自动启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,或者可以手动使用命令bgrewriteaof来重新。
保留可以恢复数据的最小指令集的含义
举个例子:比如有个key
一开始你set k1 v1
然后改成set k1 v2
最后改成set k1 v3
如果不重写,那么这3条语句都在aof文件中,内容占空间不说启动的时候都要执行一遍,共计3条命令;但是,我们实际效果只需要setk1 v3这一条, 所以,开启重写后,只需要保存set k1 v3就可以了只需要保留最后一次修改值, 相当于给aof文件瘦身减肥,性能更好。
AOF重写不仅降低了文件的占用空间,同时更小的AOF也可以更快地被Redis加载。
触发机制
可分为自动触发和手动触发
- 根据上次重写后的aof大小,判断当前aof大小是不是增长了1倍
- 重写时满足的文件大小超过64mb
如果上次aof文件大小为32mb,插入许多数据,导致增加到64mb,此时就会触发aof重写机制
删除之前的全部aof和rdb,清除干扰项
完成上述正确配置,重启redis服务器,执行set k1 v1查看aof文件是否正常
appendonly.aof.1.incr.aof文件内部
可以发现incr.aof文件大小为0,而base.aof文件大小从0变为了117,并且它们的名字也发生了改变,可以看看base.aof内部数据
里面只记录了可以恢复数据的最小指令集
手动触发
插入数据,然后使用命令bgrewriteaof
,然后查看aof文件
此时还没有到达触发条件,使用bgrewriteaof强制触发重写机制,对应的aof文件也发生了改变
重写机制的原理:
在重写即将开始之际,redis 会创建(fork)一个“重写子进程”,这个子进程会首先读取现有的 AOF 文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的 AOF 文件中,这样做是保证原有的 AOF 文件的可用性,避免在重写过程中出现意外。
当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新 AOF 文件中。
当追加结束后,redis 就会用新 AOF 文件来代替旧 AOF 文件,之后再有新的写指令,就都会追加到新的 AOF 文件中了。
小总结
AOF文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成个新的文件后去替换原来的AOF文件。
官方文档明确告诉我们能进行混合持久化
RDB + AOF: You can also combine both AOF and RDB in the same instance.
从配置文件中也能看出,aof和rdb能同时共存,但是在redis启动时,会加载aof,而不是rdb,因此aof的优先级更高
RDB和AOF如何选择,用哪个?
同时开启
将配置文件中的aof-use-rdb-preamble改为yes
在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RB文件保存的数据集要完整。
RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),留着rdb作为一个万一的手段。
RDB+AOF混合模式
结合了RDB和AOF的优点,既能快速加载又能避免丢失过多的数据。
RDB镜像做全量持久化,AOF做增量持久化
先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。-----》AOF包括了RDB头部+AOF混写
redis是基于内存的数据库,最主要,最重要的功能就是做缓存,如果开启了rdb或者aof持久化功能,或多或少会降低redis的性能。假设我们要做高并发,高性能的缓存服务器时,干脆关闭持久化功能,不需要redis做备份,备份的事由其他东西做。
同时关闭RDB和AOF
禁用rdb
禁用rdb持久化模式下,我们仍然可以使用命令save、bgsave生成rdb文件
禁用aof