第一节、Redis持久化之RDB
1、Redis持久化操作总体介绍
官网介绍:www.redis.io
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失【断电即失】。所以Redis提供了持久化功能
Redis把内部数据以文件形式在硬盘中保存一份【备份】,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)里,数据保存到硬盘的过程就称为“持久化”效果。
redis有两种持久化【备份】方式:
- 一种是"(RDB)(Redis DataBase)"快照持久化:默认开启,一次性把某时间段中redis内存中全部的数据直接保存一份存储在硬盘中【以文件形式写入】,如果数据非常多(10-20G)就不合适频繁操作该持久化操作。
- 一种是“AOF持久化”(Append Only File):把用户执行的每个“写”指令(添加/修改/删除)都备份到文件中,还原数据的时候就是执行具体写指令而已。开启AOF持久化(会清空redis内部的数据,最好在redis使用之前就开启它)。简单来说就是以追加的形式将全部内容数据写入文件中去。
2、RDB是什么
在指定的时间间隔内将Redis内存中的数据集快照写入磁盘【备份,即保存在磁盘中的文件形式是dump.rdb文件】,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。Redis默认的就是RDB,一般情况下不需要修改这个配置
备份是如何执行的?
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件【dump.rdb文件】中,待持久化过程都结束了,再用这个最新的临时文件替换上次旧的持久化好的文件,文件保存在磁盘上。
整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失 。
Fork?
Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“ 写时复制技术 ”
一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
3、RDB快照配置介绍
每次我们启动Redis的时候,都会自动产生一个dump.rdb文件。你在哪个目录启动redis,就会在哪个目录里面生成这个文件【这就是Redis后台备份的原因】
在前面我们讲过redis.conf这个配置文件,里面就有我们的关于SNAPSHOTTING快照的配置,如下:
#
# Save the DB on disk:
# 将数据库存储在磁盘上
#
# save <seconds> <changes>
#
# Redis Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
# 会在指定的秒数和数据量变化次数之后将数据写在磁盘上
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
# 下面的例子将会进行把数据写入磁盘的操作:
# 900秒(15分钟)之后,且至少1次变更
# 300秒(5分钟)之后,且至少10次变更
# 60秒之后,且至少10000次变更
#
# Note: you can disable saving completely by commenting out all "save" lines.
# 注意:你可以通过注释掉所有“save”来禁用保存
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
# 就像下面的例子,也可以删除之前所有保存的配置,通过添加单个空字符串的方式来指向:
#
# save ""
save 900 1 //15分钟改了1次
save 300 10
save 60 10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# 默认如果开启了RDB快照(至少一个save指令),Redis将会停止接受写入操作且
# 最新的后台保存将会失败。
# This will make the user aware (in a hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# disaster will happen.
# 这必须要让用户意识到(一种困难的方式)数据没有持久化到硬盘上,否则改变将不会有人注意到
# 并且一些灾难将会发生。
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
# 如果后台保存进程能重新开始工作,Redis将自动再次允许写操作。
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usual even if there are problems with disk,
# permissions, and so forth.
# 然而,如果你已经对Redis服务器和持久化进行了适当的设置,你可能想要禁止这个功能
# 以便于即使Redis的磁盘出现了问题也可以向平时一样正常的继续工作,等等。
#
stop-writes-on-bgsave-error yes
# Compress string objects using LZF when dump .rdb databases?
# 导出.rdb数据库时使用LZF压缩字符串对象?
# For default that's set to 'yes' as it's almost always a win.
# 默认设置为“yes”因为这几乎总是正确的。
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
# 如果在保存子节点时你想节省一点CPU的话可以把这个值设为“no”,但是如果你有可压缩的key或者
# value的话那么数据文件可能会更大。
rdbcompression yes
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file.
# 自RDB版本5以后,CRC64校验和被放在了文件的最后。
# This makes the format more resistant to corruption but there is a performance
# hit to pay (around 10%) when saving and loading RDB files, so you can disable it
# for maximum performances.
# 这使得文件格式更加可靠,但是在生产和加载RDB文件时有一个性能消耗(大约百分之十),
# 所以你可以关掉它来获得更好的性能。
#
# RDB files created with checksum disabled have a checksum of zero that will
# tell the loading code to skip the check.
# 禁用校验和创建的RDB文件校验和为0,这将告诉代码加载时跳过检查
rdbchecksum yes
# The filename where to dump the DB
# 转储数据库文件名
dbfilename dump.rdb
# The working directory.
# 工作目录
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
# 数据库会被写到这个目录下,文件名就是上面的“dbfilename”配置的值
#
# The Append Only File will also be created inside this directory.
# 累加的文件也会放在这个目录下面。
#
# Note that you must specify a directory here, not a file name.
# 注意这里你指定的必须是目录而不是文件名
dir ./
这个快照配置主要用来做持久化操作,下面对其中比较重要的几个配置做一些分析:
save:
这里是用来配置触发Redis的持久化条件,也就是什么时候将内存中的数据保存到硬盘。默认如下配置:
- save 900 1:表示900 秒内Redis如果至少有 1 个 key 的值变化,则保存,即进行持久化操作
- save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存,太长了可以改成120s
- save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存
当然如果你只是用Redis的缓存功能,不需要持久化,那么你可以注释掉所有的 save 行来禁用保存功能。可以直接一个空字符串来实现停用:save ""
记住:改完了配置要进行Redis重启:
stop-writes-on-bgsave-error :
默认值为yes。当启用了RDB进行持久化且最后一次后台保存数据失败,决定Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了
rdbcompression
默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。
rdbchecksum
默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验[检验完整性],但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
dbfilename
设置快照的文件名,默认是 dump.rdb
dir
设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。使用上面的 dbfilename 作为保存的文件名。通过config get dir可以查看
4、RDB持久化流程
写时复制技术,用临时文件【rdb文件】写内容,再用临时文件替换上次持久化好的rdb文件
触发机制:
- save规则满足的情况下,会自动触发rdb规则
- 执行
flushall命令,也会触发rdb规则 - 退出Redis,也会产生rdb文件
- 从而备份就自动生成一个
dump.rdb文件
针对RDB方式的持久化,手动触发可以使用:
-
save:会阻塞当前Redis服务器,直到持久化完成,线上应该禁止使用。-
set 112 good ok save ok #这样的话就会马上执行,不用等默认配置里面的时间,手动进行 -
save时只管保存,其它不管,全部阻塞。手动保存持久化。不建议。
-
-
bgsave:该触发方式会fork一个子进程,由子进程负责持久化过程,因此阻塞只会发生在fork子进程的时候。- Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求,比如处理前台输入的数据
- 可以通过lastsave 命令获取最后一次成功执行快照的时间
而持久化的自动触发的场景主要是有以下几点:
- 根据我们的
save配置规则自动触发rdb规则; - 从节点全量复制时,主节点发送rdb文件给从节点完成复制操作,主节点会触发bgsave`;
- 执行
debug reload时; - 执行
shutdown退出Redis时,如果没有开启aof,也会触发,也会产生rdb文件 - 执行
flushall命令,也会触发rdb规则
从而备份就自动生成一个dump.rdb文件,由于 save 基本不会被使用到,我们重点看看 bgsave 这个命令是如何完成RDB的持久化的。流程图如下
- Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof(aof文件重写命令)的子进程,如果在执行则bgsave命令直接返回。
bgsave/bgrewriteaof的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题。
- 父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令;
- 父进程fork后,bgsave命令返回”Background saving started”信息并不再阻塞父进程,并可以响应其他命令;
- 子进程根据父进程内存快照生成临时快照文件rdb文件,完成后对原有文件进行原子替换;
- 子进程发送信号给父进程表示完成,父进程更新统计信息。
5、Redis备份与恢复
5.1、流程
从上述练习中,可得出关于rdb文件的备份与恢复流程
rdb文件的备份:
- 先通过
config get dir查询rdb文件的目录 - 将
*.rdb的文件拷贝cp到当前Redis的启动目录
rdb的恢复:
- 关闭Redis:shutdown---生成一个新的dump.rdb文件,空的
- 把上述备份的文件拷贝到工作目录下
cp dump2.rdb dump.rdb。从而覆盖这个空的rdb文件 - 重写启动Redis, 备份数据会直接加载
5.2、练习
1、开启两个客户端,一个用于练习测试,一个用于查看。
2、客户端1:启动Redis
cd user/local/bin //redis安装目录
redis-server /etc/redis.conf
redis -cli -p 6379 //多个端口启动方式
登录客户端1后,设置12个值:模拟变更10次命令【设置save 120 10】
set k1 v1
set k2 v2
set k3 v3
set k4 v4
set k5 v5
set k6 v6
set k7 v7
set k8 v8
set k9 v9
set k10 v10
set k11 v11
set k12 v12
客户端2:查看redis安装目录bin目录下的文件
cd user/local/bin
ls-l
结果:发现里面没有dump.rdb文件。为啥?因为120s还没有到,持久化机制没有触发,过了120s后就有了,于是这里就完成我们内容的备份了,备份到了dump.rdb文件【自动完成】。因为120秒内新增12个key,所以生成了dump.rdb文件.
3、我们备份了,就应该在项目开发的时候进行恢复,注意:在企业开发中,我们经常是有干活的机器和一台备份的机器,因为如果某一天我们这个开发干活的机器坏了,我们还可以从备份机器中进行恢复。这里我们在客户端2用复制一份dump.rdb文件来演示这个备份机器
#复制一份dump.rdb文件
cp dump.rdb dump_bk.rdb
#查看,有两个rdb文件
ls-l
4、客户端1查看key
keys * #v1-v12都有,说明我们持久化起到作用了
5、客户端1模拟开发机器出故障:
FLUSHALL
shutdown //关机
exit
6、客户端2再次查看bin目录下文件
ls-l #生成两个rdb文件,其中一个是最新的,说明FLUSHALL、shutdown都会触发持久化
FLUSHALL、shutdown都会触发持久化,生成dump.rdb文件,只不过文件里面是空的。
7、客户端1进行重启:按理来说重启后,我们reids服务器应该会从硬盘读取rdb文件,恢复里面的内容至内存,但是通过我们keys *查看,发现是空的,说明我们redis内存里面没有东西,言外之意就是没有恢复成功,为什么呢?
redis-server /etc/redis.conf
redis -cli -p 6379
keys *
(empty list or set)//空的
因为我们执行了命令FLUSHALL,清空了里面的内容,并且客户端1执行shutdown,会触发持久化开始,生成新的dump.rdb文件,但是这个文件是空的,因为执行了FLUSHALL操作,导致覆盖了上一次save持久化保存的文件。
8、删除新的这个RDB文件,别用这个去覆盖,因为是空的,用原先复制的dump_bk.rdb文件进行恢复
rm -f dump.rdb
cp dump_bk.rdb dump.rdb
9、客户端1,重启查看
redis-server /etc/redis.conf
redis -cli -p 6379
keys *
发现数据恢复了,但是少了k12,这就是rdb的缺陷--最后一次的数据可能会消失
6、RDB总结
RDB是一个非常紧凑的文件,RDB在保存RDB文件时,父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程 来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能
与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些,但是数据丢失风险大,RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些亳秒级不能相应客户端请求
优势
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
劣势
- Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
- 虽然Redis在fork时使用了 写时拷贝技术 ,但是如果数据庞大时还是比较消耗性能。
- 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
如何停止
- 动态停止RDB:
redis-cli config set save "",save后给空值,表示禁用保存策略
第二节、Redis持久化之AOF
1、背景介绍
我们知道RDB有个缺点:所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改,造成恢复有困难,从工作上来,实话讲影响不大,但是总有人追求完美化,有人解决了这个问题,但从实际效果来说,有可能损失1s左右的数据,于是就更好恢复了。
在谈到aof之前,我们先谈论一个数学问题,比如从1加到100,高斯可不是按次序一个一个加的,用了更加灵巧的方法。与之类似,假如我们这里有另外一种需求:如下执行
set k1 1 #写操作
incr k1
......省略10万条相同命令
如上,在我们redis里面,有大量这样相同的操作,我们aof进行备份的时候,一摸一样的进行命令的克隆,执行,恢复的时候在从头到尾读一遍,这样保证了绝对正确,并且每次执行时间为1s,你写一条我备份一条,但是这样有些问题:当如上述大量数据命令出现的时候, appendonly.aof文件就会面临资源爆炸,从而占用磁盘空间。但是反过来站在计算机角度想,我们可以直接进行incr k1 100000,不就完了。所以现在我们来探讨一下AOF这个持久化机制。
2、AOF是什么
以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来( 读操作不记录 ),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
3、AOF持久化流程
- 客户端的请求写命令会被append追加到AOF缓冲区内;
- AOF缓冲区根据AOF持久化策略[always,everysec,no]将写操作sync同步到磁盘的AOF文件中;
- AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
- Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
4、AOF配置
# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
# 默认情况下,Redis异步地将数据集转储到磁盘上。这种模式在许多应用程序中已经足够好了,
# 但是Redis进程或断电可能导致几分钟的写丢失(取决于配置的保存点)
#
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
# Append Only文件是另一种持久性模式,它提供了更好的持久性。例如,使用默认的数据fsync
# 策略(请参阅配置文件的后面部分)Redis在服务器断电之类的突发事件中只会损失一秒钟的写
# 操作,或者如果Redis进程本身发生了错误,但操作系统仍然正常运行,则只会损失一次写操
# 作。
#
# AOF and RDB persistence can be enabled at the same time without problems.
# 可以同时启用AOF和RDB持久性,不会出现任何问题。
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
# 如果在启动时启用了AOF,则Redis将加载AOF,这是具有更好持久性保证的文件
#
# Please check http://redis.io/topics/persistence for more information.
appendonly no
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
# fsync()调用告诉操作系统实际在磁盘上写入数据,而不是在输出缓冲区中等待更多的数据。
# 一些操作系统会真正地刷新磁盘上的数据,而另一些操作系统只是试图尽快完成。
#
# Redis supports three different modes:
# Redis支持三种不同的模式:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# no:不用同步,只要让操作系统在需要的时候刷新数据即可。更快。
# always: fsync after every write to the append only log. Slow, Safest.
# always:每次写入仅追加日志后同步。缓慢的,安全的
# everysec: fsync only one time every second. Compromise.
# everysec:每秒只同步一次。折衷。
#
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
# 默认值是“everysec”,因为这通常是速度和数据安全性之间的正确折衷。
# 这取决于您是否可以将这个值放宽到“no”,以便操作系统在需要时刷新输出缓冲区,以获得更好
# 的性能(但是,如果您能够接受一些数据丢失的想法,请考虑默认的持久性模式,即快照),或
# 者相反,使用“always”,这是非常慢的,但比每秒钟都要安全一点。
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# 如果不确定,使用“everysec”。
# appendfsync always
appendfsync everysec
# appendfsync no
# When the AOF fsync policy is set to always or everysec, and a background
# saving process (a background save or AOF log background rewriting) is
# performing a lot of I/O against the disk, in some Linux configurations
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
# 当AOF fsync策略被设置为always或everysec,并且后台保存进程(后台保存或AOF日志后台
# 重写)对磁盘执行大量I/O操作时,在某些Linux配置中,Redis可能会在fsync()调用上阻塞太
# 长时间。注意,目前还没有对此进行修复,因为即使在不同的线程中执行fsync也会阻塞我们的
# 同步write(2)调用。
#
# In order to mitigate this problem it's possible to use the following option
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
# 为了缓解这个问题,可以使用下面的选项来防止在执行BGSAVE或BGREWRITEAOF时在主进程中调
# 用fsync()。
#
# This means that while another child is saving, the durability of Redis is
# the same as "appendfsync none". In practical terms, this means that it is
# possible to lose up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
# 这意味着当另外一个子进程正在保存时,Redis的持久性与“appendfsync none”相同。
# 实际上,这意味着在最坏的情况下可能会损失30秒的日志(使用默认的Linux设置)
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.
# 如果您有延迟问题,请将此选项变为“yes”。否则,从耐久性的角度来看,将其设置为“不”是最
# 安全的选择。
no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.
# 自动重写只追加文件
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
# 当日志大小以指定的百分比增长时,Redis能够隐式调用BGREWRITEAOF自动重写日志文件
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
# 这就是它的工作原理:Redis记得最近一次重写后AOF文件的大小(如果重启后没有发生重写,则
# 使用启动时AOF的大小)
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
# 这个基准大小和当前大小做比较。如果当前大小大于指定的百分比,则会触发重写。
# 此外,您还需要为要重写的AOF文件指定最小大小,这对于避免重写AOF文件很有用,即使达到了
# 增加的百分比,但仍然非常小。
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.
# 指定0的百分比,以禁用自动AOF重写特性
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# An AOF file may be found to be truncated at the end during the Redis
# startup process, when the AOF data gets loaded back into memory.
# This may happen when the system where Redis is running
# crashes, especially when an ext4 filesystem is mounted without the
# data=ordered option (however this can't happen when Redis itself
# crashes or aborts but the operating system still works correctly).
# 在Redis启动过程的最后,当AOF数据加载回内存时,可能会发现AOF文件被截断。
# 当运行Redis的系统崩溃时可能会发生这种情况,特别是在没有data=ordered选项的情况下挂
# 载ext4文件系统时(然而,当Redis本身崩溃或中止时,这不会发生,但操作系统仍然正常工
# 作)
#
# Redis can either exit with an error when this happens, or load as much
# data as possible (the default now) and start if the AOF file is found
# to be truncated at the end. The following option controls this behavior.
# 发生这种情况时,Redis可以带着错误退出,或者加载尽可能多的数据,如果发现AOF文件在末尾
# 被截断,则可以启动。以下选项控制此行为。
#
# If aof-load-truncated is set to yes, a truncated AOF file is loaded and
# the Redis server starts emitting a log to inform the user of the event.
# Otherwise if the option is set to no, the server aborts with an error
# and refuses to start. When the option is set to no, the user requires
# to fix the AOF file using the "redis-check-aof" utility before to restart
# the server.
# 如果将AOF -load-truncated设置为yes,就会加载一个截短的AOF文件,并且Redis服务器
# 开始发出日志来通知用户该事件。否则,如果将该选项设置为no,服务器将以错误中止并拒绝启
# 动。当该选项设置为no时,用户需要在重启服务器之前使用“redis-check-aof”实用程序修复
# AOF文件。
#
# Note that if the AOF file will be found to be corrupted in the middle
# the server will still exit with an error. This option only applies when
# Redis will try to read more data from the AOF file but not enough bytes
# will be found.
# 注意,如果AOF文件在中间被破坏,服务器仍然会带着错误退出。这个选项只适用于当Redis试图
# 从AOF文件中读取更多数据,但没有找到足够的字节时。
aof-load-truncated yes
# When rewriting the AOF file, Redis is able to use an RDB preamble in the
# AOF file for faster rewrites and recoveries. When this option is turned
# on the rewritten AOF file is composed of two different stanzas:
# 当重写AOF文件时,Redis能够在AOF文件中使用RDB序言,以便更快地重写和恢复。启用此选项
# 后,重写的AOF文件由两个不同的节组成:
#
# [RDB file][AOF tail]
#
# When loading Redis recognizes that the AOF file starts with the "REDIS"
# string and loads the prefixed RDB file, and continues loading the AOF
# tail.
# 当加载Redis时,识别出AOF文件以“Redis”字符串开始并加载前缀RDB文件,然后继续加载AOF
# 尾部。
aof-use-rdb-preamble yes
1、AOF默认不开启
与RDB不同的是,RDB默认是开启的,可以在redis.conf中配置进行开启配置
appendonly no ---yes
RDB开启后,默认生成的文件是dump.rdb,而AOF开启后默认为 appendonly.aof
AOF文件的保存路径,同RDB的路径一致【默认Redis启动目录】。
2、AOF和RDB 同时开启,redis听谁的?
AOF和RDB同时开启,系统默认取AOF的数据(数据不会存在丢失)
set k1 v1 #写操作
set k2 v2
set k3 v3
set k4 v4
set k5 v5
set k6 v6
set k7 v7
如上所示:这是上次我们redis里面设置的内容,我们在配置里面开启AOF,重启Redis以后,但是我们执行keys *命令却发现没有数据【按理来说应该恢复了,rdb里面有内容】,这就是因为我们开启了aof,因为开启了之后我们没有进行任何写操作的命令,所以aof这个文件为空,并且要听aof的。所以没有内容。【启动reids以后aof就会开启,aof文件就会生成】
3、FLUSHALL
set k1 v1 //写操作
set k2 v2
set k3 v3
set k4 v4
FLUSHALL
如上所示,执行上述写操作命令,我们shutdown重启恢复以后,我们知道会生成一个新的空的rdb文件【执行了FLUSHALL操作】,同时,由于开启了aof,所以也会生成aof文件,此时我们执行keys *命令发现没有数据,因为aof里面也记录了FLUSHALL命令【可以cat查看】,所以数据都清掉了,为空【所以实际情况中不会写FLUSHALL】。删掉这个FLUSHALL命令,重启Redis以后,就可以自动恢复。
5、AOF备份/修复/恢复
AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。
正常恢复【同rdb】
- 修改默认的appendonly no,改为yes
- 将有数据的aof文件复制一份保存到对应目录(查看目录:config get dir)
- 恢复:重启redis然后重新加载
异常恢复
- 修改默认的appendonly no,改为yes
- 备份被写坏的AOF文件
- 如遇到 AOF文件损坏【里面有错误内容】,要通过
/usr/local/bin/redis-check-aof--fix appendonly.aof命令进行恢复【ls-l】 - 恢复:重启redis,然后重新加载
6、AOF同步频率设置
appendfsync always
始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好
appendfsync everysec
出厂默认推荐,异步操作,每秒同步,每秒就记入日志一次,如果宕机,本秒的数据可能丢失。
appendfsync no
redis不主动进行同步,把同步时机交给操作系统,此时效率最高
7、Rewrite压缩
7.1、概述
是什么:
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof
重写原理,如何实现重写
AOF文件持续增长而过大时,会fork出一条新子进程来将文件重写(也是先写临时文件最后再rename),redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作。
no-appendfsync-on-rewrite:
如果 no-appendfsync-on-rewrite=yes ,不写入aof文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)
如果 no-appendfsync-on-rewrite=no, 还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)
触发机制,何时重写
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发,重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。
auto-aof-rewrite-percentage:**设置重写的基准值,文件达到100%时开始重写(**文件是原来重写后文件的2倍时触发)auto-aof-rewrite-min-size:设置重写的基准值,最小文件64MB。达到这个值开始重写。
例如:文件达到70MB开始重写,降到50MB,下次什么时候开始重写?100MB
系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,
如果Redis的AOF当前大小>= base_size +base_size*100% (默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写。【实际3G起步】
7.2、重写流程
- bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。
- 主进程fork出子进程执行重写操作,保证主进程不会阻塞。
- 子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
- 4.1-子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。4.2-主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
- 使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。
8、小结
优势
- 备份机制更稳健,丢失数据概率更低。
- 读的日志文本,通过操作AOF稳健,可以处理误操作。
劣势
- 比起RDB占用更多的磁盘空间。
- 恢复备份速度要慢,所以默认的就是RDB持久化
- 每次读写都同步的话,有一定的性能压力。
- 存在个别Bug,造成恢复不能。
小总结
AOF文件是一个只进行追加的日志文件,Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写,AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析也很轻松
对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积,根据所使用的fsync策略,AOF的速度可能会慢于RDB
用哪个好:官方推荐两个都启用。
- 如果对数据不敏感,可以选单独用RDB。不建议单独用 AOF,因为可能会出现Bug。
- 如果只是做纯内存缓存,可以都不用,即都关闭
官网建议
- RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
- AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾。
- Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
- 只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
同时开启两种持久化方式:
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
- 建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
性能建议