Featured image of post redis持久化

redis持久化

本文阅读量

redis的持久化

redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以redis提供了持久化功能!

RDB(快照)

是什么

在内存中的数据库记录定时dump到磁盘上的RDB持久化

rdb保存的文件是dump.rdb

触发机制

触发 RDB 持久化过程分为手动触发自动触发

手动触发

触发命令:savebgsave

save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用

bgsave 命令:Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短

Redis 内部所有的涉及 RDB 的操作都采用 bgsave 的方式

自动触发

在Redis配置文件中的save指定到达触发RDB持久化的条件,就开启RDB数据同步。

1
2
3
4
5
6
# 900s内至少达到一条写命令
save 900 1
# 300s内至少达至10条写命令
save 300 10
# 60s内至少达到10000条写命令
save 60 10000

这种通过服务器配置文件触发RDB的方式,与bgsave命令类似,达到触发条件时,会forks一个子进程进行数据同步

文件处理

保存

RDB 文件保存在 dir 配置指定的目录下,文件名通过 dbfilename 配置指定。可以通过执行config set dir{newDir}config set dbfilename{newFileName}运行期动态执行,当下次运行时 RDB 文件会保存到新目录。

当遇到坏盘或磁盘写满等情况时,可以通过config set dir{newDir}在线修改文件路径到可用的磁盘路径,之后执行 bgsave 进行磁盘切换,同样适用于AOF 持久化文件。

压缩

Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数config set rdbcompression{yes|no}动态修改。

虽然压缩 RDB 会消耗 CPU,但可大幅降低文件的体积,方便保存到硬盘或通过网络发送给从节点,因此线上建议开启

恢复

只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候会自动检查 dump. rdb恢复其中的数据!可以通过config get dir来获取rdb文件存放位置

优缺点

优点

  1. RDB 是一个非常紧凑的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
  2. RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
  3. RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

缺点

  1. RDB 方式数据没办法做到实时持久化/秒级持久化,如果服务器宕机的话,采用RDB的方式会造成某个时段内数据的丢失,比如我们设置10分钟同步一次或5分钟达到1000次写入就同步一次,那么如果还没 达到触发条件服务器就死机了,那么这个时间段的数据会丢失。
  2. 使用bgsave命令在forks子进程时,如果数据量太大,forks的过程也会发生阻塞,另外,forks子进程会耗费内存。 针对 RDB 不适合实时持久化的问题,Redis 提供了 AOF 持久化方式来解决。

aof持久化过程

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snaρshot快照,它恢复的是将快照文件直接读到内存里。

1)执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。

2)父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞,通过 info stats 命令查看 latest_fork_usec 选项,可以获取最近一 个 fork 操作的耗时,单位为微秒。

3)父进程 fork 完成后,bgsave 命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。

4)子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选项。

5)进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence 下的 rdb_* 相关选项。

补充

rdb文件生成时机

1、save的规则满足的情况下,会自动触发rdb规则(save 900 1,900秒内至少有一次修改则触发保存操作)

2、执行 flushall命令,也会触发我们的rdb规则!

3、退出redis,也会产生rdb文件!

AOF

是什么

AOF持久化方式会记录客户端对服务器的每一次操作日志以追加方式保存到以后缀为aof文件末尾,恢复的时候就把这个文件全部在执行一遍!

Aof保存的是 appendonly.aof文件

默认是不开启的,我们需要手动进行配置!我们只需要将 appendonly改为yes就开启了aof!

触发机制

手动触发

直接调用bgrewriteaof命令

自动触发

aof默认就是文件的无限追加,文件会越来越大!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
appendonly no # 是否开启aof

appendfilename "appendonly.aof" #AOF文件名

dir ./ #RDB文件和AOF文件所在目录

# 持久化策略
appendsync always # 数据发生变化立即记录到磁盘中
appendsync everysec # 每1秒钟将数据变化记录到磁盘中(默认)
appendsync no # 缓存区满了,就刷新到磁盘中

# 如果aof文件大于64m!fork一个新的进程来将我们的文件进行重写
auto-aof-rewrite-percentage 100 #当前 AOF 文件空间(aof_current_size)和上一次重写后 AOF 文件空间(aof_base_size)的比值
auto-aof-rewrite-min -size 64mb #AOF 重写时文件最小体积

aof-load-truncated yes #如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件

文件处理

保存

AOF将客户端的每一个写操作都追加到aof文件末尾

压缩/重写

随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入 AOF 重写机制压缩文件体积

所谓重写:是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程,比如:多条命令可以合并为一个,如:lpush list alpush list blpush list c 可以转化为:lpush list a b c

AOF 重写降低了文件占用空间,除此之外,另一个目的是:更小的 AOF 文件可以更快地被 Redis 加载。

恢复

优缺点

优点

  1. AOF可以设置 完全不同步、每秒同步、每次操作同步,默认是每秒同步。因为AOF是操作指令的追加,所以可以频繁的大量的同步。
  2. AOF文件是一个追加日志的文件,即使服务宕机为写入完整的命令,也可以通过redis-check-aof工具修复这些问题。
  3. 如果AOF文件过大,Redis会在后台自动地重写AOF文件。重写后会使AOF文件压缩到最小所需的指令集。
  4. AOF文件是有序保存数据库的所有写入操作,易读,易分析。即使如果不小心误操作数据库,也很容易找出错误指令,恢复到某个数据节点。例如不 小心FLUSHALL,可以非常容易恢复到执行命令之前。

缺点

  1. 相同数据量下,AOF的文件通常体积会比RDB大。因为AOF是存指令的,而RDB是所有指令的结果快照。但AOF在日志重写后会压缩一些空间。
  2. 在大量写入和载入的时候,AOF的效率会比RDB低。因为大量写入,AOF会执行更多的保存命令,载入的时候也需要大量的重执行命令来得到最后的结 果。 RDB对此更有优势。

aof执行过程

1)所有的写入命令会追加到 aof_buf(缓冲区)中。

2)AOF 缓冲区根据对应的策略向硬盘做同步操作。

3)随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。

4)当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。

以日志的形式来记录每个写操作,将Reds执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件, redis启动之初会读取该文件重新构建数据,换言之, redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

1)执行 AOF 重写请求。 如果当前进程正在执行 AOF 重写,请求不执行并返回如下响应: ERR Background append only file rewriting already in progress

2)父进程执行 fork 创建子进程,开销等同于 bgsave 过程。

3.1)主进程 fork 操作完成后,继续响应其他命令。所有修改命令依然写入 AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证原有 AOF 机制正确 性。

3.2)由于 fork 操作运用写时复制技术,子进程只能共享 fork 操作时的内存数据。由于父进程依然响应命令,Redis 使用“AOF 重写缓冲区”保存这部 分新数据,防止新 AOF 文件生成期间丢失这部分数据。

4)子进程根据内存快照,按照命令合并规则写入到新的 AOF 文件。每次批量写入硬盘数据量由配置 aof-rewrite-incremental-fsync 控制,默认为 32MB,防止单 次刷盘数据过多造成硬盘阻塞。

4.1)新 AOF 文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,具体见 info persistence 下的 aof_*相关统计。

4.2)父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件。

4.3)使用新 AOF 文件替换老文件,完成 AOF 重写。

重启,redis就可以生效了!

如果这个aof文件有错误,这时候 redis是启动不起来的,我们需要修复这个aof文件

redis给我们提供了一个工具redis-check-aof --fix file.aof

如果文件正常,重启就可以直接恢复了!

持久化选择

在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用RDB或 AOF的一种,或同时开启RDB和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能, 而且主机master和从机slave可以独立的选择持久化方案。

对以下场景来讨论持久化策略的选择:

  • 如果Redis中的数据完全丢弃也没有关系(如Redis完全用作DB层数据的cache),那么无论是单机, 还是主从架构,都可以不进行任何持久化。

  • 在单机环境下(对于个人开发者,这种情况可能比较常见),如果可以接受十几分钟或更多的数据丢失,选择RDB对Redis的性能更加有利; 如果只能接受秒级别的数据丢失,应该选择AOF。

  • 配置了主从环境,slave的存在既可以实现数据的热备,也可以进行读写分离分担Redis读请求, 以及在master宕掉后继续提供服务。在这种情况下的做法是:

    • master:完全关闭持久化(包括RDB和AOF),这样可以让master的性能达到最好;

    • slave:关闭RDB,开启AOF(如果对数据安全要求不高,开启RDB关闭AOF也可以),并定时对持久化文件进行备份(如备份到其他文件夹,并标记 好备份的时间);然后关闭AOF的自动重写,然后添加定时任务,在每天Redis闲时(如凌晨12点)调用bgrewriteaof。

      注意:这里需要解释一下,为什么开启了主从复制,可以实现数据的热备份,还需要设置持久化呢?因为在一些特殊情况下,主从复制仍然不足以保证 数据的安全,例如: master和slave进程同时停止:考虑这样一种场景,如果master和slave在同一个机房,则一次停电事故就可能导致master和slave机器同时关 机,Redis进程停止;如果没有持久化,则面临的是数据的完全丢失。 master误重启:考虑这样一种场景,master服务因为故障宕掉了,如果系统中有自动拉起机制(即检测到服务停止后重启该服务)将master自动 重启,由于没有持久化文件,那么master重启后数据是空的, slave同步数据也变成了空的;如果master和slave都没有持久化,同样会面临数据的完全丢失。需要注意的是,即便是使用了哨兵进行 自动的主从切换, 也有可能在哨兵轮询到master之前,便被自动拉起机制重启了。因此,应尽量避免“自动拉起机制”和“不做持久化”同时出现。

  • 异地灾备:上述讨论的几种持久化策略,针对的都是一般的系统故障,如进程异常退出、宕机、断电等,这些故障不会损坏硬盘。但是对于一些可 能导致硬盘损坏的灾难情况,如火灾地震,就需要进行异地灾备。

    • 例如对于单机的情形,可以定时将RDB文件或重写后的AOF文件,通过scp拷贝到远程机器,如阿里云;对于主从的情形,可以定时在master上执行 bgsave,然后将RDB文件拷贝到远程机器, 或者在slave上执行bgrewriteaof重写AOF文件后,将AOF文件拷贝到远程机器上。 一般来说,由于RDB文件文件小、恢复快,因此灾难恢复常用RDB文件;异地备份的频率根据数据安全性的需要及其它条件来确定,但最好不要低于 一天一次。

配置方案

企业级的持久化的配置策略

1
2
3
4
5
save 60 10000 #如果你希望尽可能确保说,RDB最多丢1分钟的数据,那么尽量就是每隔1分钟都生成一个快照,低峰期,数据量很少,也没必要
10000->生成RDB,1000->RDB #这个根据你自己的应用和业务的数据量,你自己去决定
# AOF一定要打开,fsync,everysec
auto-aof-rewrite-percentage 100 #就是当前AOF大小膨胀到超过上次100%,上次的两倍
auto-aof-rewrite-min-size 64mb #根据你的数据量来定,16mb,32mb

数据备份方案

RDB非常适合做冷备,每次生成之后,就不会再有修改了

数据备份方案

  1. 写crontab定时调度脚本去做数据备份
  2. 每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份
  3. 每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份
  4. 每次copy备份的时候,都把太旧的备份给删了
  5. 每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去【crontab】

扩展

1、RDB持久化方式能够在指定的时间间隔内对你的数据进行快照存储

2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以 Redis协议追加保存每次写的操作到文件末尾, Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

3、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用仼何持久化

4、同时开启两种持久化方式

  • 在这种情况下,当 redis重启的时候会优先载入AoF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
  • RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的Bug,留着作为一个万一的手段。

5、性能建议

  • 因为RDB文件只用作后备用途,建议只在 Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。
  • 如果 Enable aof,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是 AOF rewrite的最后将 rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 aof rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值
  • 如果不 Enable AOF,仅靠 Master- Slave Replication实现高可用性也可以,能省掉一大笔IO,也减少了 rewrite时带来的系统波动。代价是如果 Master/Slave同时倒掉(断电),会丢失十几分钟的数据,启动脚本也要比较两个 Master/ Slave中的RDB文件,载入较新的那个,微博就是这种架构。
使用 Hugo 构建
主题 StackJimmy 设计