一、AOF概述
AOF(Append-Only File)记录Redis中每次的写命令,类似mysql中的binlog,服务重启时会重新执行AOF中的命令将数据恢复到内存中,RDB(按策略持久化)持久化方式记录的粒度不如AOF(记录每条写命令),因此很多生产环境都是开启AOF持久化。AOF中记录了操作和数据,在日志文件中追加完成后才会将内存中的数据进行变更。
AOF(append only file)只追加文件,记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。
二、AOF持久化流程
#1.客户端的请求写命令会被append追加到AOF缓冲区内;
#2.AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
#3.AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
#4.Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
三、 AOF配置
开启了AOF之后,RDB就默认不使用了。使用下面的配置开启AOF以及策略。(如果使用AOF,推荐选择always方式持久化,否则在高并发场景下,每秒钟会有几万甚至百万条请求,如果使用everysec的方式的话,万一服务器挂了那几万条数据就丢失了)。
#开启AOF持久化
appendonly yes
#AOF文件名
appendfilename "appendonly.aof"
#AOF文件存储路径 与RDB是同一个参数
dir "/opt/app/redis6/data"
#AOF策略,一般都是选择第一种[always:每个命令都记录],[everysec:每秒记录一次],[no:看机器的心情高兴了就记录]
appendfsync always
# appendfsync everysec
# appendfsync no
#aof文件大小比起上次重写时的大小,增长100%(配置可以大于100%)时,触发重写。[假如上次重写后大小为10MB,当AOF文件达到20MB时也会再次触发重写,以此类推]
auto-aof-rewrite-percentage 100
#aof文件大小超过64MB时,触发重写
auto-aof-rewrite-min-size 64mb
#是否在后台写时同步单写,默认值no(表示需要同步).这里的后台写,表示后台正在重写文件(包括bgsave和bgrewriteaof.bgrewriteaof网上很多资料都没有涉及到。其实关掉bgsave之后,主要的即是aof重写文件了).no表示新的主进程的set操作会被阻塞掉,而yes表示新的主进程的set不会被阻塞,待整个后台写完成之后再将这部分set操作同步到aof文件中。但这可能会存在数据丢失的风险(机率很小),如果对性能有要求,可以设置为yes,仅在后台写时会异步处理命令.
no-appendfsync-on-rewrite no
# 指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,yes会log并继续,而no会直接恢复失败.
aof-load-truncated yes
四、AOF持久化策略
AOF分别有三种备份策略,分别是[always:每个命令都记录],[everysec:每秒记录一次],[no:看机器的心情高兴了就记录],针对这三种策略给出如下说明。
1.策略说明
策略 |
说明 |
优点 |
always |
每次执行,都会持久化到AOF文件中 |
不丢失数据 |
everysec |
每秒持久化一次 |
减少IO |
no |
根据服务器性能持久化 |
全自动 |
2.策略抉择
命令 |
Always |
Everysec |
no |
优点 |
不丢失数据 |
每秒一次fsync,减少IO |
不用管,全自动 |
缺点 |
IO开销大 |
丢1秒钟的数据 |
不可控 |
五、AOF模式的优点
1.使用AOF Redis会更具有可持久性(durable):你可以有很多不同的fsync策略:没有fsync,每秒fsync,每次请求时fsync。使用默认的每秒fsync策略,写性能也仍然很不错(fsync是由后台线程完成的,主线程继续努力地执行写请求),即便你也就仅仅只损失一秒钟的写数据。
2.AOF日志是一个追加文件,所以不需要定位,在断电时也没有损坏问题。即使由于某种原因文件末尾是一个写到一半的命令(磁盘满或者其他原因),redis-check-aof工具也可以很轻易的修复。
3.当AOF文件变得很大时,Redis会自动在后台进行重写。重写是绝对安全的,因为Redis继续往旧的文件中追加,使用创建当前数据集所需的最小操作集合来创建一个全新的文件,一旦第二个文件创建完毕,Redis就会切换这两个文件,并开始往新文件追加。
4.AOF文件里面包含一个接一个的操作,以易于理解和解析的格式存储。你也可以轻易的导出一个AOF文件。例如,即使你不小心错误地使用FLUSHALL命令清空一切,如果此时并没有执行重写,你仍然可以保存你的数据集,你只要停止服务器,删除最后一条命令,然后重启Redis就可以。
总结:
1)备份机制更稳健,丢失数据概率更低。
2)可读的日志文本,通过操作AOF稳健,可以处理误操作。
六、AOF重写机制
1.AOF重写机制概述
1.因为 AOF 的运作方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加, AOF 文件的体积也变得越来越大。举个例子,如果你对一个计数器调用了 100 次 INCR ,那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录。然而在实际上,只使用一条 SET 命令已经足以保存计数器的当前值了,其余 99 条记录实际上都是多余的。
2.为了处理这种情况, Redis 支持一种有趣的特性:可以在不断服务客户端的情况下,对 AOF 文件进行重建。执行 BGREWRITEAOF 命令, Redis 将生产一个新的 AOF 文件,这个文件包含重建当前数据集所需的最少命令。
2. AOF重写配置
配置名 |
含义 |
appendonly |
开启AOF持久化功能 |
auto-aof-rewrite-min-size |
触发重写的最小尺寸 |
auto-aof-rewrite-percentage |
AOF文件增长率 |
aof_current_size |
AOF当前尺寸 |
aof_base_size |
AOF上次启动和重写的尺寸(单位:字节) |
3. AOF重写触发机制
根据配置,AOF持久化触发机制如下:
1.aof_current_size > auto-aof-rewrite-min-size
2.(aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage
4. AOF重写流程
1.bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。
2.主进程fork出子进程执行重写操作,保证主进程不会阻塞。
3.子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
4.子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。2).主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
5.使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。
七、AOF持久化缺点
1.对同样的数据集,AOF文件通常要大于等价的RDB文件。
2.AOF可能比RDB慢,这取决于准确的fsync策略。通常fsync设置为每秒一次的话性能仍然很高,如果关闭fsync,即使在很高的负载下也和RDB一样的快。不过,即使在很大的写负载情况下,RDB还是能提供能好的最大延迟保证。
3.在过去,我们经历了一些针对特殊命令(例如,像BRPOPLPUSH这样的阻塞命令)的罕见bug,导致在数据加载时无法恢复到保存时的样子。这些bug很罕见,我们也在测试套件中进行了测试,自动随机创造复杂的数据集,然后加载它们以检查一切是否正常,但是,这类bug几乎不可能出现在RDB持久化中。为了说得更清楚一点:Redis AOF是通过递增地更新一个已经存在的状态,像MySQL或者MongoDB一样,而RDB快照是一次又一次地从头开始创造一切,概念上更健壮。
但是,
1)要注意Redis每次重写AOF时都是以当前数据集中的真实数据从头开始,相对于一直追加的AOF文件(或者一次重写读取老的AOF文件而不是读内存中的数据)对bug的免疫力更强。
2)我们还没有收到一份用户在真实世界中检测到崩溃的报告。
总结:
1)比起RDB占用更多的磁盘空间。
2)恢复备份速度要慢。
3)每次读写都同步的话,有一定的性能压力。
4)存在个别Bug,造成恢复不能。
八、AOF持久化优缺点总结
优点:可以最大程度保证数据不丢失
缺点:日志记录量级比较大
九、RDB与AOF抉择
1.RDB与AOF比较
命令 |
RDB |
AOF |
启动优先级 |
低 |
高 |
体积 |
小 |
大 |
恢复速度 |
快 |
慢 |
数据安全性 |
丢数据 |
根据策略的不同,丢数据的情况也不同 |
轻重 |
重 |
轻 |
2.官网建议
1.RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
2.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.
3.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
4.只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
5.同时开启两种持久化方式
6.在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据, 因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
7.RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份), 快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
8.性能建议
因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。
如果使用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。
代价,一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。
只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。
默认超过原大小100%大小时重写可以改到适当的数值。
3. RDB与AOF之间的优劣势
#1.RDB的优点
1.压缩后的二进制文件,适用于备份、全量复制及灾难恢复。
2.RDB恢复数据性能优于AOF方式。
#2.RDB的缺点
1.无法做到实时持久化,每次都要创建子进程,频繁操作成本过高
2.保存后的二进制文件,不同版本直接存在兼容性问题
#3.AOF的优点
1.以文本形式保存,易读
2.记录写操作保证数据不丢失
#4.AOF的缺点
1.存储所有写操作命令,且文件为文本格式保存,未经压缩,文件体积高。
2.恢复数据时重放AOF中所有代码,恢复性能弱于RDB方式。
十、 AOF与RDB混合
看了上面的RDB和AOF的介绍后,我们可以发现,使用RDB持久化会有数据丢失的风险,但是恢复速度快,而使用AOF持久化可以保证数据完整性,但恢复数据的时候会很慢。于是从Redis4之后新增了混合AOF和RDB的模式,先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB何AOF两部分恢复数据,即保证了数据完整性,又提高了恢复的性能。
开启混合模式后,每当bgrewriteaof命令之后会在AOF文件中以RDB格式写入当前最新的数据,之后的新的写操作继续以AOF的追加形式追加写命令。当redis重启的时候,加载 aof 文件进行恢复数据:先加载 rdb 的部分再加载剩余的 aof部分。
1.混合配置
修改下面的参数即可开启AOF,RDB混合持久化
aof-use-rdb-preamble yes
2.混合模式示例
开启混合持久化模式后,重写之后的aof文件里和rdb一样存储二进制的快照数据,继续往redis中进行写操作,后续操作在aof中仍然是以命令的方式追加。因此重写后aof文件由两部分组成,一部分是类似rdb的二进制快照,另一部分是追加的命令文本。
# step1: 进入Redis, 写入数据
[root@alvin-test-os redis]# redis-cli --raw
127.0.0.1:6379> set name alvin
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> set add 上海
OK
127.0.0.1:6379> exit
# Step 2: 查看备份文件
[root@alvin-test-os redis]# ll data/
总用量 8
-rw-r--r--. 1 root root 121 11月 24 15:39 appendonly.aof
-rw-r--r--. 1 root root 116 11月 24 15:39 dump.rdb
[root@alvin-test-os redis]# cat data/appendonly.aof | grep add
add
[root@alvin-test-os redis]# cat data/appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$4
name
$5
alvin
*3
$3
set
$3
age
$2
18
*3
$3
set
$3
add
$6
上海
# Step 3: 启动备份
[root@alvin-test-os redis]# redis-cli --raw
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
127.0.0.1:6379> exit
# Step 4: 查看配置文件发现AOF备份文件变成了二进制文件
[root@alvin-test-os redis]# cat data/appendonly.aof
REDIS0009� redis-ver6.0.9�
�edis-bits�@�ctime��_used-mem��4
aof-preamble���namealvinadd上海age���6����&
[root@alvin-test-os redis]#
# Step 5: 再次写入文件
[root@alvin-test-os redis]# redis-cli --raw
127.0.0.1:6379> set company 上海
OK
127.0.0.1:6379> exit
# Step 6:再次查看备份文件发现被分成了两份,一份二进制,一份AOF备份
[root@alvin-test-os redis]# cat data/appendonly.aof
REDIS0009� redis-ver6.0.9�
�edis-bits�@�ctime��_used-mem��4
aof-preamble���namealvinadd上海age���6����&*2
$6
SELECT
$1
0
*3
$3
set
$7
company
$15
上海
3.备份Redis数据
1.Redis 对于数据备份是非常友好的,因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建,就不会进行任何修改。
2.当服务器要创建一个新的 RDB 文件时,它先将文件的内容保存在一个临时文件里面,当临时文件写入完毕时,程序才使用临时文件替换原来的 RDB 文件。
3.这也就是说,无论何时, 复制 RDB 文件都是绝对安全的。
#以下是我们的建议:
1.创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
2.确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
3.至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。
4.RDB持久化高级配置
1.Redis 对于数据备份是非常友好的,因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建,就不会进行任何修改。
2.当服务器要创建一个新的 RDB 文件时,它先将文件的内容保存在一个临时文件里面,当临时文件写入完毕时,程序才使用临时文件替换原来的 RDB 文件。
3.这也就是说,无论何时, 复制 RDB 文件都是绝对安全的。
#以下是我们的建议:
1.创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
2.确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
3.至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。
5.AOF持久化高级配置
#编辑配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#正在导出rdb快照的过程中,要不要停止同步aof
no-appendfsync-on-rewrite yes
#aof文件大小比起上次重写时的大小,增长率100%时重写,缺点:业务开始的时候,会重复重写多次
auto-aof-rewrite-percentage 100
#aof文件,至少超过64M时,重写
auto-aof-rewrite-min-size 64mb