消息中间件——Redis—持久化(十)

前言

通常 Redis 将数据存储在内存中或虚拟内存中,它是通过以下两种方式实现对数据的持久化。

RDB 快照方式(默认持久化方式)

这种方式就是将内存中数据以快照的方式写入到二进制文件中 ,默认的文件名为dump.rdb。

  1. 手动触发

    客户端可以使用 save 或者 bgsave 命令通知 redis 做一次快照持久化。

    save 操作是在主线程中保存快照的,由于 redis 是用一个主线程来处理所有客户端的请求,这种方式会阻塞所有客户端请求。所以不推荐使用。

    bgsave 操作时Redis主进程会fork一个子进程来完成RDB的过程,完成后自动结束(操作系统的多进程Copy On Write机制,简称COW)。所以Redis主进程阻塞时间只有fork阶段的那一下。相对于save,阻塞时间很短。

    另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步增量数据。如果数据量大的话,写操作会比较多,必然会引起大量的磁盘 IO 操作,可能会严重影响性能。

    注意:由于快照方式是在一定间隔时间做一次的,所以如果 redis 意外当机的话,就会丢失最后一次快照后的所有数据修改。

  2. 自动触发

    场景一:配置redis.conf,触发规则,自动执行:

    # 当在规定的时间内,Redis发生了写操作的个数满足条件,会触发发生BGSAVE命令。
    # save <seconds> <changes>
    # 当用户设置了多个save的选项配置,只要其中任一条满足,Redis都会触发一次BGSAVE操作
    save 900 1 
    save 300 10 
    save 60 10000
    # 以上配置的含义:900秒之内至少一次写操作、300秒之内至少发生10次写操作、
    # 60秒之内发生至少10000次写操作,只要满足任一条件,均会触发bgsave

    场景二:执行shutdown命令关闭服务器时,如果没有开启AOF持久化功能,那么会自动执行一次bgsave

    场景三:主从同步(slave和master建立同步机制)

  3. RDB 执行过程

    Redis 使用操作系统的多进程 cow(Copy On Write) 机制来实现RDB快照持久化

    • 执行bgsave命令的时候,Redis主进程会检查是否有子进程在执行RDB/AOF持久化任务,如果有的话,直接返回

    • Redis主进程会fork一个子进程来执行执行RDB操作,fork操作会对主进程造成阻塞(影响Redis的读写),fork操作完成后会发消息给主进程,从而不再阻塞主进程。(阻塞仅指主进程fork子进程的过程,后续子进程执行操作时不会阻塞)

    • RDB子进程会根据Redis主进程的内存生成临时的快照文件,持久化完成后会使用临时快照文件替换掉原来的RDB文件。(该过程中主进程的读写不受影响,但Redis的写操作不会同步到主进程的主内存中,而是会写到一个临时的内存区域作为一个副本)

    • 子进程完成RDB持久化后会发消息给主进程,通知RDB持久化完成(将上阶段内存副本中的增量写数据同步到主内存)

  4. RDB的优缺点

    优点

    • RDB文件小,非常适合定时备份,用于灾难恢复

    • Redis加载RDB文件的速度比AOF快很多,因为RDB文件中直接存储的是内存数据,而AOF文件中存储的是一条条命令,需要重演命令。

      缺点:

    • RDB无法做到实时持久化,若在两次bgsave间宕机,则会丢失区间(分钟级)的增量数据,不适用于实时性要求较高的场景

    • RDB的cow机制中,fork子进程属于重量级操作,并且会阻塞redis主进程

    • 存在老版本的Redis不兼容新版本RDB格式文件的问题

AOF 增量持久化

AOF日志是持续增量的备份,是基于写命令存储的可读的文本文件。

AOF日志会在持续运行中持续增大,由于Redis重启过程需要优先加载AOF日志进行指令重放以恢复数据,恢复时间会无比漫长。

所以需要定期进行AOF重写,对AOF日志进行瘦身。目前AOF是Redis持久化的主流方式。

  1. 开启方式

    AOF默认是关闭的,通过redis.conf配置文件进行开启

    ## 只有在“yes”下,aof重写/文件同步等特性才会生效  
    appendonly yes  
    
    ## 指定aof文件名称  
    appendfilename appendonly.aof  
    
    ## 指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec  
    appendfsync everysec  
    ## 在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”  
    no-appendfsync-on-rewrite no  
    
    ## aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”  
    auto-aof-rewrite-min-size 64mb  
    
    ## 相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比  
    ## 每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A)
    ## aof文件增长到A*(1 + p)之后,触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。  
    auto-aof-rewrite-percentage 100

    AOF是文件操作,对于变更操作比较密集的server,那么将造成磁盘IO的负荷加重。

    此外linux对文件操作采取了“延迟写入”手段,即并非每次write操作都会触发实际磁盘操作,而是进入了buffer中,当buffer数据达到阀值时触发实际写入(也有其他时机),这是linux对文件系统的优化。这样的持久化还是有可能会丢失部分修改

    所以Linux 的glibc提供了fsync(int fd)函数可以将指定文件的内容强制从内核缓存刷到磁盘。只要 Redis 进程实时调用 fsync 函数就可以保证 aof 日志不丢失。

    但是 fsync 是一个磁盘 IO 操作,它很慢!如果 Redis 执行一条指令就要 fsync 一次,那么 Redis 高性能的地位就不保了。

    因此在上述配置文件中,可观察到Redis中提供了3中AOF记录同步选项:

    • always:每一条AOF记录都立即同步到文件,性能很低,但较为安全。
    • everysec:每秒同步一次,性能和安全都比较中庸的方式,也是redis推荐的方式。如果遇到物理服务器故障,可能导致最多1秒的AOF记录丢失。
    • no:Redis永不直接调用文件同步,而是让操作系统来决定何时同步磁盘。性能较好,但很不安全。
  2. 重写机制

    日志追加方式同时带来了另一个问题。持久化文件会变的越来越大。此时就需要对AOF进行重写,瘦身。

    AOF Rewrite 虽然是“压缩”AOF文件的过程,但并非采用“基于原AOF文件”来重写或压缩,而是采取了类似RDB快照的方式:基于Copy On Write,全量遍历内存中数据,然后逐个序列到AOF文件中。因此AOF rewrite能够正确反应当前内存数据的状态。

    AOF重写(bgrewriteaof)和RDB快照写入(bgsave)过程类似,二者都消耗磁盘IO。Redis采取了“schedule”策略:无论是“人工干预”还是系统触发,快照和重写需要逐个被执行。

    重写过程中,对于新的变更操作将仍然被写入到原AOF文件中,同时这些新的变更操作也会被Redis收集起来。当内存中的数据被全部写入到新的AOF文件之后,收集的新的变更操作也将被一并追加到新的AOF文件中。然后将新AOF文件重命名为appendonly.aof,使用新AOF文件替换老文件,此后所有的操作都将被写入新的AOF文件。

    AOF重写默认大小64m太小 可改5g以上 避免重写频繁,在4.0之前会将相同的操作进行合并(比如连续使用set进行了三次,重写会将这三次合并成一次命令存到文件中,这样文件就会变小),在 4.0之后是混合持久化。

  3. 重写触发机制

    和RDB类似,AOF触发机制也分为:手动触发和自动触发

    手动触发

    直接调用bgrewriteaof命令

    redis-cli -h ip -p port bgrewriteaof

    自动触发

    根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机

    auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认为64MB(我们线上是512MB)。
    auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的值

    其中aof_current_size和aof_base_size可以在info Persistence统计信息中查看。

  4. AOF 优缺点

    优点

    • AOF只是追加写日志文件,对服务器性能影响较小,速度比RDB要快,消耗的内存较少

      缺点

    • AOF方式生成的日志文件太大,需要不断AOF重写,进行瘦身。
      即使经过AOF重写瘦身,由于文件是文本文件,文件体积较大(相比于RDB的二进制文件)。

    • AOF重演命令式的恢复数据,速度显然比RDB要慢。

Redis 4.0 混合持久化

  • 仅使用RDB快照方式恢复数据,由于快照时间粒度较大,会丢失大量数据。
  • 仅使用AOF重放方式恢复数据,日志性能相对 rdb 来说要慢。在 Redis 实例很大的情况下,启动需要花费很长的时间。

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。

混合持久化同样也是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据。

大量数据使用粗粒度(时间上)的rdb快照方式,性能高,恢复时间快。增量数据使用细粒度(时间上)的AOF日志方式,尽量保证数据的不丢失。

开启混合持久化

4.0版本的混合持久化默认关闭的,通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是禁用的,可通过config set修改。

在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。

持久化设置

  1. RBD和AOF建议同时打开(Redis4.0之后支持)
  2. RDB做冷备,AOF做数据恢复(数据更可靠)
  3. RDB采取默认配置即可,AOF推荐采取everysec每秒策

数据备份

我们需要定时备份rdb文件来做冷备,为什么?

不是有aof和rbd了吗为什么还要单独写定时任务去备份?

因为Redis的aof和rdb是仅仅有一个最新的,比如谁手贱再Redis宕机的时候执行rm -rf aof/rdb了,那不就GG了吗?或者rdb/aof文件损坏了等不可预期的情况。所以我们需要单独备份rdb文件以防万一。

数据恢复

  1. redis挂了

    如果仅仅是redis进程挂了,那么直接重启redis进程即可,Redis会按照持久化配置直接基于持久化文件进行恢复数据。

    如果有AOF则按照AOF,AOF和RDB一起开的话也走AOF。

  2. 持久化文件丢了

    如果持久化文件(rdb/aof)损坏了,或者直接丢失了。那么就要采取我们上面所做的rdb备份来进行恢复了。

    方案一:直接把备份的rdb扔到redis持久化目录下然后重启redis

    不行的原因在于:redis是按照先aof后rdb进行恢复的,所以都是开启aof的,redis启动后会重新生成新的aof文件,里面是空的。所以不会进行任何数据恢复,也就是说虽然你把rdb丢给redis了,但是redis会按照aof来恢复,而aof是redis启动的时候新生成的空文件,所以不会有任何数据进行恢复。

    方案二:那么我们把rdb文件丢给redis后,先将redis的aof关闭再启动redis进程不就能按照rdb来进行恢复了吗?

    是这样的,没毛病!但是新的问题来了,我们aof肯定要开的,aof对数据保障更可靠。那什么我们按照rdb文件恢复完后再修改redis配置文件开启aof然后重启redis进程不就得了嘛?大哥…你打开aof然后重启redis,这时候redis又会生成一个空的aof文件,这时候恢复的时候又是啥数据都没了。

    可行方案:我不管你是持久化文件丢了还是坏了,我都先rm -rf * 给他删了。

    • 停止redis进程
    • 删除坏掉的rdb和aof持久化文件。
    • 修改配置文件关闭redis的aof持久化。
    • 找到最新备份的rdb文件扔到redis的持久化目录里。(这里最新的肯定是按照小时备份的最后一个)
    • 启动Redis进程
    • 执行set appendonly yes动态打开aof持久化。
    • 等aof文件生成后再修改redis配置文件打开aof。
    • 重启redis进程。

数据迁移

  1. scan+MIGRATE

    先scan出key,然后使用redis自带命令MIGRATE执行建的迁移。
    说明:MIGRATE命令在redis>=2.6.0版本才有,Redis3.06版本之后支持迁移多个键。

  2. dump

    现在源redis执行dump命令,该redis的所有数据会序列化成rdb文件;然后把rdb文件拷贝到目标redis,重启目标redis。
    说明:这种方式优点是操作简单,不需要研发再另外写程序迁移。缺点是:需要运维手动操作。

  3. scan+hset/set

    先scan出key,然后判断这个key属于哪种类型,执行对应的写命令hset、set等。

文章目录
  1. 1. 前言
  2. 2. RDB 快照方式(默认持久化方式)
  3. 3. AOF 增量持久化
  4. 4. Redis 4.0 混合持久化
  5. 5. 持久化设置
  6. 6. 数据备份
  7. 7. 数据恢复
  8. 8. 数据迁移
|