Redis持久化机制详解

Redis持久化机制详解

一. 持久化的意义

  1. Redis持久化的意义:主要在于故障恢复。Redis如果仅将数据完全保存在内存中,是无法应对灾难性故障的。如果Redis进程突然挂掉,保存在内存中的数据就全没了,如果没有持久化,后果不堪设想。使用持久化+定期备份(如备份到云存储上)的机制,可以在很大程度上解决Redis故障恢复的问题。这样即使Redis服务宕机,且磁盘损坏,也可以从云存储上拉取备份的数据进行恢复,不会造成数据的全部丢失。
  2. 从一定意义上来说,Redis的持久化也可以视为高可用的一部分。因为如果没有持久化和数据恢复,一旦Redis宕机,即使重启,数据也都没了,这样大量的请求过来,由于没有命中缓冲,就会直接打到MySQL上,造成缓存雪崩,这样一来MySQL很有可能就挂了,整个系统就瘫痪了。如果持久化方案做的很好,即使Redis宕机,也可以快速重启并恢复数据,重新回到可用状态。

二. 持久化方式

  1. Redis持久化方式

    1. RDB:每隔一段时间,就会对当前Redis内存中的数据生成一份全量的快照文件
    2. AOF:将对数据的操作记录写在aof日志文件中(此时是将数据写入操作系统的OS Cache中),然后每隔一段时间(可配置,默认1s)调用操作系统的fsync操作,强制将OS Cache刷到磁盘文件中。Redis只会写一个AOF文件,这样会导致AOF文件越来越大,当AOF文件膨胀到一定程度时,AOF会进行rewrite操作,基于当前Redis内存中最新的数据,重新构造一个新的更小的AOF文件,然后删除旧的大AOF文件。
  2. 持久化相关细节

    1. 由于内存的大小是一定的,当Redis内存中的数据达到上限时,Redis会基于淘汰算法(默认LRU),自动清除一部分数据。
    2. 如果同时开启了RDB和AOF两种持久化策略,则Redis重启时,会默认通过AOF文件重新构建数据库,因为AOF文件中的数据更为完整。
  3. RDB的优缺点

    1. 优点

      1. RDB会生成多个文件,每个文件都代表了当时时刻Redis的全量数据,因此RDB文件十分适合用来做冷备份,可以定时生成备份文件,并保存到安全的云存储上。
      2. 由于进行RDB持久化时,主进程只需fork一个子进程,由子进程来执行RDB文件的IO操作,因此对Redis对外提供服务的影响较小,可以让Redis保存高性能。而AOF每次都需要写文件,虽然可以快速写入OS Cache,但是还是需要一定的时间开销,肯定比RDB略慢一些。
      3. 通过RDB文件恢复数据比AOF文件更快。因为RDB存放的是数据快照,恢复时直接加载到内存中即可。而AOF存放的是指令日志, 恢复的时候需要重放和执行指令。

      综合以上优点,RDB特别适合用来做冷备份

    2. 缺点

      1. 一般来说,RDB持久化的时间间隔要比AOF更长,因此可能丢失更多的数据。这也是RDB最大的缺点,也因此RDB不适应做第一优先恢复方案。
      2. RDB在fork子进程来执行文件生成时,如果文件较大,可能会导致对客户端的服务暂停几毫秒,甚至几秒。
  4. AOF的优缺点

    1. 优点

      1. AOF可以更好的维护数据的完整性。一般情况下,AOF的时间间隔是1s,因此最多丢失1s的数据。
      2. AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。
      3. AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。在创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。
      4. AOF日志文件的命令通过人类可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据。
    2. 缺点

      1. 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大。

      2. AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件。当然,每秒一次fsync,性能也还是很高的。

        如果要保证一条数据都不丢,也是可以的,将AOF的fsync设置成每写入一条数据,就fsync一次即可。但是这样会导致Redis的QPS大降,并不建议。

      3. 以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。

      4. 唯一的比较大的缺点,其实就是做数据恢复的时候,会比较慢。而且做冷备、定期的备份不太方便,可能要自己手写复杂的脚本去做。

  5. 持久化方案最佳实践

    建议同时开启AOF和RDB。

    1. 如果仅仅使用RDB,可能会造成大量数据的丢失。
    2. 如果仅仅使用AOF,则丢失了RDB冷备份的优势,仅仅通过AOF恢复数据会比较慢。
    3. 综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复。

三. RDB机制

  1. RDB配置及命令

    RDB机制默认开启

    #每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快#照,这个操作也被称之为snapshotting
    save 60 1000
    

    快照也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成。

    save可以设置多个,就是多个snapshotting检查点。每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件

  2. RDB工作流程

    1. Redis根据配置的save时间,生成检查点。每到一个检查点,就会去check一下,该时间间隔内是否有超过指定数量的key发生了变化。
    2. 如果有超过指定数量的key发生了变化,则Redis会fork一个子进程。
    3. 子进程尝试将数据dump到一个临时的rdb文件中。
    4. rdb快照文件生成后,用新的文件替换旧的dump.rdb。
  3. 一些细节

    1. 每个Redis进程,同一时刻只会存在一个dump.rdb文件。新生成的快照会将旧的覆盖。
    2. 通过redis-cli shutdown这种方式去停掉redis,其实是一种安全退出的模式,redis在退出的时候会将内存中的数据立即生成一份完整的rdb快照。
    3. 如果Redis意外宕机,且当前时间还未到检查点,则这段时间内产生的数据并不会持久化到快照文件中,就会丢失数据。可以通过kill -9模拟。

四. AOF机制

  1. AOF配置

    AOF机制默认关闭,需要手动开启

    #开启AOF
    appendonly yes
    
    #AOF 的fsync策略
    # appendfsync always
    appendfsync everysec
    # appendfsync no
    
  2. AOF工作流程

    Redis开启AOF策略后,每接收到一条写命令,都会将该日志写入OS Cache中,然后调用操作系统的fsync()函数将日志写入磁盘。Redis提供了三种fsync的时机:

    1. always:每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低。除非要求确保一条数据都不丢失,否则不建议使用这个配置。
    2. everysec:每秒将OS Cache中的数据fsync到磁盘。这是默认配置,一般生产环境下也使用此配置,性能有保障,QPS还是可以上万的。
    3. no:完全依赖操作系统底层的fsync机制,在Redis层面不可控,可能会造成数据丢失,不建议使用。
  3. AOF rewrite机制

    Redis内存中的数据是不断变化的,可能会自动化过期,也可能被手动删除。而且,由于内存大小的限制,Redis当内存占用量超过一定值时,会通过淘汰策略清除一部分key。这样一来,可能导致一些已经在内存中不存在的数据仍然保持在AOF日志文件中,AOF文件可能会膨胀地很大。因此,Redis提供了AOF rewrite的机制,会在后台对AOF文件进行重写,以缩小文件的容量。

    Redis 2.4之前,需要手动开发一些脚本,去定时通过BGREWRITEAOF命令去执行AOF rewrite。但是redis 2.4之后,会自动进行rewrite操作。

    用户可以配置rewrite的触发条件:

    #当AOF文件增长到上次的百分之多少时,触发rewrite
    auto-aof-rewrite-percentage 100
    
    #执行rewrite所需的最小文件大小
    auto-aof-rewrite-min-size 64mb
    
  4. rewrite 执行流程

    1. Redis fork子进程
    2. 子进程基于当前Redis内存中的数据,构建日志,创建一个新的临时的AOF文件并执行写入操作。
    3. Redis主进程会继续接收客户端的写请求,将日志写入内存,同时也会写入旧的AOF文件。
    4. 子进程写完新的AOF文件后,主进程会将这段时间内内存中生成的新日志追加到新的AOF文件中。
    5. 写入完成,用新的AOF文件替换旧的。
  5. AOF文件的修复

    如果Redis在向AOF文件append日志时,突然宕机,可能会导致AOF文件由于不完整而破损。此时,可以通过redis-check-aof --fix命令来修复破损的AOF文件。redis-check-aof命令会删除不完整的AOF日志。

五. AOF和RDB同时工作

  1. RDB的snapshotting操作和AOF的rewrite操作不会同时执行。
  2. 如果RDB在执行snapshotting时,用户执行BGREWRITEAOF命令,那么等RDB快照生成之后,才会去执行AOF rewrite。
  3. 如果dump.rdb文件和appendonly.aof文件同时存在,那么redis重启的时候,会优先使用AOF进行数据恢复,因为其中的日志更完整。

六. 企业级数据备份方案

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

数据备份的主要目的是出现数据错误时进行恢复。

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

七. 企业级数据恢复方案

  1. 如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据。默认的fsync配置,最多丢失1s的数据。
  2. 如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,直接基于AOF日志文件进行数据恢复。如果AOF文件有破损,可以通过redis-check-aof脚本进行修复。
  3. 如果redis当前最新的AOF和RDB文件都出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复。这种情况多为人为因素引起,如误删数据等。
  4. 如果当前机器上的所有RDB文件全部损坏,那么从远程的云服务上拉取最新的RDB快照回来恢复数据。
  5. 如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了,那么可以选择某个更早的时间点,对数据进行恢复

八. 补充

  1. 热备份 VS 冷备份
    1. 热备份:实时备份,服务不停止,数据是最新的。
    2. 冷备份:周期性备份(如:定时每天凌晨开始备份,备份时服务暂时停止。备份的数据不是最新的。
  2. 通过RDB文件恢复数据的步骤
    1. 关闭Redis
    2. **修改配置文件,禁用掉AOF功能。这一步非常重要。**如果AOF功能处于开启状态,则Redis重启时优先会通过AOF文件恢复数据,即使AOF文件不存在,也会创建一个空的,这样一来无法通过备份的RDB文件进行数据恢复。
    3. 将备份的RDB文件拷贝到数据目录下
    4. 重启Redis,验证数据是否已恢复。
    5. **通过Redis客户端热修改配置,开启AOF功能,使得AOF和RDB文件中的数据保持一致这一步也很重要。**如果不通过这种方式开启AOF,而是通过重启Redis修改配置文件的方式,则又会出现2中的问题,导致数据丢失。
    6. 修改配置文件,开启AOF功能,重启Redis。这样数据就完全恢复了。

你可能感兴趣的:(redis)