您的位置:首页 > 数据库 > Redis

详解redis:RDB持久化和AOF持久化

2020-04-25 18:41 573 查看

《Redis设计与实现》笔记

RDB持久化通过保存数据库中的键值对来记录数据库状态,
而AOF持久化通过保存Redis服务器执行的写命令来记录数据库状态

一、RDB的创建和载入

有两个命令可以生成RDB文件,一个是SAVE,一个是BGSAVE。
SAVE命令会阻塞服务器进程,直到RDB文件完成创建,在服务器阻塞期间,服务器不能处理任何命令请求。
BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程会继续处理命令请求。BGSAVE命令可以通过设置服务器配置的save选项设置多个条件,当其中任一条件满足时,会自动执行BGSAVE命令。
例如:

save 900 1 //服务器在900s之内,对数据库进行了至少一次修改
save 300 10 //服务器在300s之内,对数据库进行了至少三次修改
save 60 10000 //服务器在60s之内,对数据库进行了至少10000次修改

那么服务器是如何检查条件是否满足的呢?
Redis的服务器周期操作函数serverCron默认每隔100ms就会执行一次,这个函数其中一项工作就是检查save设置中的条件是否满足,如果满足则执行BGSAVE选项。
RDB文件的载入则是在服务器启动时自动载入的,载入过程中服务器进程处于阻塞状态。

二、RDB文件压缩功能

假设服务器开启了文件压缩功能(redis.conf文件中rdbccompression)
当字符串对象的编码为RAW
如果这个字符串的长度小于等于20字节,那么这个字符串会被原样保存,
如果这个字符串大于20字节,这个字符串会被压缩后保存(ZF压缩算法)

三、AOF持久化的实现

当AOF持久化功能处于打开时,服务器在执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾。
服务器在执行完一个事件循环之前,会调用一个flushAppendOnlyFile函数,考虑是否要将aof_buf缓冲区中的数据写入并同步到磁盘(AOF文件)中。
写入:将aof_buf缓冲区的数据写入内存缓冲区中。
同步:将内存缓冲区的数据写入磁盘(AOF文件)中。
flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项的值来决定。
当appendfsync的值为always时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件。
当值为everysec时(默认值),服务器在每个事件循环都要将aof_buf缓冲区数据写入到内存缓冲区中,并每隔1s同步到磁盘中。
当值为no时,服务器在每个事件循环都要将aof_buf缓冲区数据写入到内存缓冲区中,但何时同步由操作系统决定。

AOF文件的载入

当服务器打开了AOF持久化功能,那么服务器会优先使用AOF文件进行载入。服务器只需读入并运行一遍AOF保存的写命令就可还原数据库之前的状态。

AOF重写

因为AOF保存的是服务器执行的写命令,随着存储的数据越来越多,如果不对AOF进行控制,那么会导致AOF体积过大。那么我们就需要用到AOF重写功能。
AOF重写并不需要对当前AOF文件的数据进行读取,分析或者写入操作,而是读取当前数据库的状态来实现的。首先从数据库读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令。但是当键的值超过redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量的值(默认64)时,会使用多条命令来记录键的值。

BGREWRITEAOF

redis服务器是使用单线程来处理命令请求的,所以并不希望AOF重写阻塞线程导致服务器无法处理客服端发来的命令请求,所以redis通过BGREWRITEAOF命令来将AOF重写放入到后台执行,那么就会导致一个问题,在子进程在进行AOF重写器件,服务器还是可以接受并执行客户端发来的命令请求,而客户端收到的命令请求需要改变数据库的数据时,如何保证服务器当前数据库状态和重写后的AOF文件所保存的数据库状态一致呢?
为了解决这个问题,redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当服务器执行完一个写命令后,它会将这个写命令发送给AOF缓冲区和AOF重写缓冲区。当子进程完成AOF重写工作后,它会向父进程发送一个信号,父进程在接受到该信号之后,会调用一个信号处理函数,并将AOF重写缓冲区的所有内容写入到新AOF文件中,然后对新AOF文件进行改名,覆盖现有的AOF文件。

RDB和AOF优劣势比较(转载来自网络)

RDB

1)优势

1.RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。

2.生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。

3.RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

2)劣势

1、RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,如果不采用压缩算法(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁执行成本过高(影响性能)

2、RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题(版本不兼容)

3、在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)

AOF

1)优势
使用 AOF 持久化会让 Redis 变得非常耐久(much more durable):你可以设置不同的 fsync 策略,比如无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。
Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

2)劣势
对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。AOF 在过去曾经发生过这样的 bug : 因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样。 (举个例子,阻塞命令 BRPOPLPUSH 就曾经引起过这样的 bug 。) 测试套件里为这种情况添加了测试: 它们会自动生成随机的、复杂的数据集, 并通过重新载入这些数据来确保一切正常。 虽然这种 bug 在 AOF 文件中并不常见, 但是对比来说, RDB 几乎是不可能出现这种 bug 的。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
小陈小陈小陈 发布了6 篇原创文章 · 获赞 0 · 访问量 147 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: