0%

redis持久化那些事儿

Redis 持久化

redis的持久化方式有两种,一种是RDB持久化,一种是AOF持久化。

RDB快照(snapshot)

redis把数据以快照的方式保存在磁盘上。默认的情况下,redis将数据保存在文件名为dump.rdb的二进制文件中。

redis在运行时,会把内存中的数据快照保存到磁盘上,在redis重启时,会从rdb文件中读取数据还原redis数据库的状态。

rdb是自动默认开启的,但并没有开启触发规则。

触发机制

RDB的触发可分为两大类,一类是自动触发,一类是手动触发。

自动触发

自动触发

当数据操作满足一定的规则,自动触发。详细规则如下

默认开启rdb,但没有配置规则,若需要使用或配置则需要在配置文件中将注释放开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# RDB自动持久化规则
# 当900 秒内有至少有 1 个键被改动时,自动进行数据集保存操作
save 900 1
# 当 300 秒内有至少有 10 个键被改动时,自动进行数据集保存操作
save 300 10
# 当 60 秒内有至少有 10000 个键被改动时,自动进行数据集保存操作
save 60 10000
# RDB持久化文件名
dbfilename dump.rdb
# 数据持久化文件存储目录
dir /var/lib/redis
# bgsave发生错误时是否停止写入,通常为yes
stop-writes-on-bgsave-error yes
# rdb文件是否使用压缩格式
rdbcompression yes
# 是否对rdb文件进行校验和检验,通常为yes
rdbchecksum yes

手动触发

save命令

在客户端执行save命令,会触发一次保存快照。save命令是同步命令,在save执行时,会占用主进程,导致redis其他命令无法使用。在数据量过大时,可能会导致redis反应变慢。

bgsave命令

bgsave命令是异步操作,执行bgsave命令保存快照,可以在生成快照的同时,依然可以正常处理其他命令。bgsave子进程是由主线程fock生成的,它不影响主进程的执行,同时还可以共享主进程的数据

save和bgsave对比

命令 save bgsave
IO类型 同步 异步
是否阻塞redis 是(在生成子进程时有短暂阻塞,速度很快,基本没有影响)
时间复杂度 O(n) O(n)
优点 不消耗额外内存 不阻塞客户端
缺点 阻塞客户端命令 需要fork子进程,消耗内存

关闭RDB

虽然这种方式可能不需要,但若需要关闭rdb的时候,在redis-shell中只需要执行即可

1
config set save ""

当然也可以在配置文件中将 save "" 注释打开,也可以。

AOF(Append Only File)

默认情况下,Redis 异步转储磁盘上的数据集。RDB模式在很多应用场景中已经足够好了,但是 Redis 进程的问题或断电可能会导致几分钟的写入丢失(取决于配置的保存点)。 Append Only File 是另一种持久性模式,可提供更好的持久性。
例如,使用默认的数据 fsync 策略(见后面的配置文件)Redis 可能会在服务器断电等戏剧性事件中丢失一秒钟的写入,或者如果 Redis 进程本身发生问题,则会丢失一次写入,但是操作系统仍然正常运行。可以同时启用 AOF 和 RDB 持久化。如果在启动时启用了 AOF,Redis 将加载 AOF,即具有更好持久性保证的文件。

AOF是通过将修改的每一条指令写入一个记录文件件appendonly.aof中(先写入os cache,每隔一段时间 fsync到磁盘)。这样子的话,在redis重启时,可以通过读取指令来重新写入数据达到重建数据库的目的。

开启AOF

可以通过修改配置文件来打开AOF功能与命令,配置文件中如下:

在配置文件中将 appendonly yes注释打开即可

1
appendonly yes

命令

1
config set appendonly yes

AOF保存策略

  • appendfsync always:每次有新命令追加到 AOF 文件时就执行一次 fsync ,非常慢,也非常安全。
  • appendfsync everysec:每秒 fsync 一次,足够快,并且在故障时只会丢失 1 秒钟的数据。
  • appendfsync no:从不 fsync ,将数据交给操作系统来处理。更快,也更不安全的选择。

推荐(也就是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

AOF重写

由于AOF不断的将命令追加到文件的末尾,因此随着命令的不断增加,AOF文件的体积会变的越来越大。

例如执行INCR命令执行了1000次,在AOF内会生成1000个操作命令。但实际上来说,只需要SET到当前值的命令就可以存储了,前面的999次INCR都是无意义的。

实际上可能不止这一种多余的废操作,因此Redis可以对AOF文件进行重写,会把命令进行精简整合成一个新的AOF文件,新的文件里包含生成当前数据的最少命令。

执行AOF重写的方式也有两种,一种是命令,一种是配置文件

配置文件配置aof重写

默认开启重写,但需要先开始aof

1
2
3
4
# 当前大小大于指定的百分比触发重写
auto-aof-rewrite-percentage 100
# AOF 文件指定最小大小
auto-aof-rewrite-min-size 64mb

将此基本大小与当前大小进行比较。如果当前大小大于指定的百分比,则触发重写。此外,您还需要为要重写的 AOF 文件指定最小大小,这对于避免重写 AOF 文件(即使达到百分比增加但仍然很小)很有用。指定百分比为零以禁用自动 AOF 重写功能。

命令

1
bgrewriteaof

RDB 与 AOF对比

RDB

优点

  • 文件紧凑,很适合进行数据备份和容灾恢复
  • 恢复大量数据时RDB速度快

缺点

  • 数据量越大,二进制保存到磁盘会耗时越久
  • 遇见意外的情况下,如宕机等,可能导致未持久化的数据完全丢失

AOF

优点

  • 可以使用不同的fsync策略,在默认的每秒fsync下,最多丢失1s的数据
  • AOF的持久化记录是文件追加,保存速度快
  • 存储的是操作命令,AOF文件易读,可以轻易的进行文件分析

缺点

  • 文件体积较RDB大
  • 重启时恢复数据速度较慢
类型 RDB AOF
启动优先级
体积
宕机恢复速度
数据安全性 可能丢失数据 每秒fsync最多丢失1s数据

是rdb还是aof?

使用可以根据需要来自行选择,如果对数据丢失不敏感的,使用rdb即可。当然在生产环境使用时,可以两种方式都启用。rdb文件可以用来做备份,aof文件来保证数据的安全性

RDB与AOF混用

必须先开启aof

在redis4.0之后,出现了一个新的持久化选项——混合持久化。    可以通过以下配置开启混合持久化
1
2
# 在配置文件中设置
aof‐use‐rdb‐preamble yes

开启混合持久化后,AOF在重写时,不是单纯的把命令写入AOF文件,而是把重写这一刻之前的内存数据做RDB快照处理,在重写之后的还是继续使用AOF命令的形式保存。这样aof文件里就有历史的RDB快照和增量的AOF命令。
我们知道,RDB文件的恢复速度比AOF快的多,因此这种混合的模式,在redis重启的时候能大大提升效率。

Redis淘汰机制

将内存使用限制设置为指定的字节数。当达到内存限制时,Redis 将尝试根据选择的驱逐策略删除键。

MAXMEMORY 策略:

当达到 maxmemory 时,Redis 将如何选择要删除的内容。可以从以下行为中选择一项

noeviction:默认禁止驱逐数据。内存不够使用时,对申请内存的命令报错。

volatile-lru:从设置了过期时间的数据集中淘汰最近没使用的数据。

volatile-ttl:从设置了过期时间的数据集中淘汰即将要过期的数据。

volatile-random:从设置了过期时间的数据中随机淘汰数据。

allkeys-lru:淘汰最近没使用的数据。

allkeys-random:随机淘汰数据。

注意:使用上述任何一种策略,当没有合适的键用于驱逐时,Redis 将在需要更多内存的写操作时返回错误。这些通常是创建新密钥、添加数据或修改现有密钥的命令。一些示例是:SET、INCR、HSET、LPUSH、SUNIONSTORE、SORT(由于 STORE 参数)和 EXEC(如果事务包括任何需要内存的命令)。

如果 Redis 无法根据策略删除键,或者如果策略设置为“noeviction”,Redis 将开始对会使用更多内存的命令(如 SET、LPUSH 等)回复错误信息,并将继续回复像 GET
这样的只读命令。简而言之…如果附加了副本,建议为 maxmemory 设置一个下限,以便系统上有一些空闲 RAM 用于副本输出缓冲区(但如果策略是“noeviction”,则不需要这样做)

警告:如果您将副本附加到启用了 maxmemory 的实例,则从使用的内存计数中减去提供副本所需的输出缓冲区的大小,以便网络问题重新同步不会触发密钥被逐出的循环,并且在将副本的输出缓冲区填满,删除键的 DEL
触发删除更多键,依此类推,直到数据库完全清空