凌风郎少 2019-06-28
持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。
持久化Redis所有数据保持在内存中,对数据的更新将异步地保存到磁盘上。
快照方式持久化就是在某时刻把所有数据进行完整备份。
例:Mysql的Dump方式、Redis的RDB方式。
写日志方式持久化就是把用户执行的所有写指令(增删改)备份到文件中,还原数据时只需要把备份的所有指令重新执行一遍即可。
例:Mysql的Binlog、Redis的AOF、Hbase的HLog。
RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。
在 Redis 运行时, RDB 程序将当前内存中的数据库快照保存到磁盘文件中, 在 Redis 重启动时, RDB 程序可以通过载入 RDB 文件来还原数据库的状态。
当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。
save
命令执行一个同步操作,以RDB文件的方式保存所有数据的快照。
127.0.0.1:6379> save OK
由于 save
命令是同步命令,会占用Redis的主进程。若Redis数据非常多时,save
命令执行速度会非常慢,阻塞所有客户端的请求。
因此很少在生产环境直接使用SAVE 命令,可以使用BGSAVE 命令代替。如果在BGSAVE命令的保存数据的子进程发生错误的时,用 SAVE命令保存最新的数据是最后的手段。
bgsave
命令执行一个异步操作,以RDB文件的方式保存所有数据的快照。
127.0.0.1:6379> bgsave Background saving started
Redis使用Linux系统的fock()
生成一个子进程来将DB数据保存到磁盘,主进程继续提供服务以供客户端调用。
如果操作成功,可以通过客户端命令LASTSAVE来检查操作结果。
save
与 bgsave
对比命令 | save | bgsave |
---|---|---|
IO类型 | 同步 | 异步 |
阻塞? | 是 | 是(阻塞发生在fock(),通常非常快) |
复杂度 | O(n) | O(n) |
优点 | 不会消耗额外的内存 | 不阻塞客户端命令 |
缺点 | 阻塞客户端命令 | 需要fock子进程,消耗内存 |
除了手动执行 save
和 bgsave
命令实现RDB持久化以外,Redis还提供了自动自动生成RDB的方式。
你可以通过配置文件对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动进行数据集保存操作。
比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有 1000 个键被改动”这一条件时, 自动进行数据集保存操作:
save 60 1000
# RDB自动持久化规则 # 当 900 秒内有至少有 1 个键被改动时,自动进行数据集保存操作 save 900 1 # 当 300 秒内有至少有 10 个键被改动时,自动进行数据集保存操作 save 300 10 # 当 60 秒内有至少有 10000 个键被改动时,自动进行数据集保存操作 save 60 10000 # RDB持久化文件名 dbfilename dump-<port>.rdb # 数据持久化文件存储目录 dir /var/lib/redis # bgsave发生错误时是否停止写入,通常为yes stop-writes-on-bgsave-error yes # rdb文件是否使用压缩格式 rdbcompression yes # 是否对rdb文件进行校验和检验,通常为yes rdbchecksum yes
快照功能(RDB)并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。 从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。
你可以在配置文件中打开AOF方式:
appendonly yes
打开AOF后, 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。这样的话, 当 Redis 重新启时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。
你可以通过配置文件配置 Redis 多久才将数据 fsync 到磁盘一次。
每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全。
每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。
推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。
从不 fsync :将数据交给操作系统来处理,由操作系统来决定什么时候同步数据。更快,也更不安全的选择。
命令 | 优点 | 缺点 |
---|---|---|
always | 不丢失数据 | IO开销大,一般SATA磁盘只有几百TPS |
everysec | 每秒进行与fsync,最多丢失1秒数据 | 可能丢失1秒数据 |
no | 不用管 | 不可控 |
推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。
因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。
为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 bgrewriteaof 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。
Redis 2.2 需要自己手动执行 bgrewriteaof 命令; Redis 2.4 则可以通过配置自动触发 AOF 重写。
bgrewriteaof 命令
Redis bgrewriteaof 命令用于异步执行一个 AOF(AppendOnly File)文件重写操作。重写会创建一个当前AOF文件的体积优化版本。
即使 bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的AOF文件在 bgrewriteaof 成功之前不会被修改。
AOF 重写由 Redis 自行触发,bgrewriteaof 仅仅用于手动触发重写操作。
具体内容:
配置名 | 含义 |
---|---|
auto-aof-rewrite-min-size | 触发AOF文件执行重写的最小尺寸 |
auto-aof-rewrite-percentage | 触发AOF文件执行重写的增长率 |
统计名 | 含义 |
---|---|
aof_current_size | AOF文件当前尺寸(字节) |
aof_base_size | AOF文件上次启动和重写时的尺寸(字节) |
AOF重写自动触发机制,需要同时满足下面两个条件:
- aof_current_size > auto-aof-rewrite-min-size
- (aof_current_size - aof_base_size) * 100 / aof_base_size > auto-aof-rewrite-percentage
假设 Redis 的配置项为:
auto-aof-rewrite-min-size 64mb auto-aof-rewrite-percentage 100
当AOF文件的体积大于64Mb,并且AOF文件的体积比上一次重写之久的体积大了至少一倍(100%)时,Redis将执行 bgrewriteaof 命令进行重写。
# 开启AOF持久化方式 appendonly yes # AOF持久化文件名 appendfilename appendonly-<port>.aof # 每秒把缓冲区的数据同步到磁盘 appendfsync everysec # 数据持久化文件存储目录 dir /var/lib/redis # 是否在执行重写时不同步数据到AOF文件 # 这里的 yes,就是执行重写时不同步数据到AOF文件 no-appendfsync-on-rewrite yes # 触发AOF文件执行重写的最小尺寸 auto-aof-rewrite-min-size 64mb # 触发AOF文件执行重写的增长率 auto-aof-rewrite-percentage 100
- | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 根据策略决定 |
一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。