Redis 提供的持久化方式
RDB
RDB持久化方式能够在指定的时间间隔对数据进行快照存储。在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。你可以对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。这种持久化方式被称为快照(snapshotting)。
Redis启动时会读取RDB快照文件,将数据从硬盘载入内存。通过 RDB 方式的持久化,一旦Redis异常退出,就会丢失最近一次持久化以后更改的数据。
RDB原理
当 Redis 需要保存 dump.rdb 文件时,服务器执行以下操作:
- 执行BGSAVE命令,Redis 父进程判断当前是否存在正在执行的子进程,如果存在,BGSAVE命令直接返回。
- 父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞。
- 父进程fork完成后,父进程继续接收并处理客户端的请求,而子进程开始将内存中的数据写进硬盘的临时 RDB 文件。
- 当子进程写完所有数据后会用该临时文件替换旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。
RDB的优点和缺点
优点:
- RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份和灾难恢复,与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。
缺点:
- 万一Redis意外宕机,你可能会丢失几分钟的数据。
- RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis来不及响应客户端的请求。AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度。
AOF
RDB并不是非常耐久(dura ble): 如果 Redis 因为某些原因而造成故障停机,那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。因此 Redis 增加了一种完全耐久的持久化方式: AOF 持久化。AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,即AOF只许追加文件但不可以改写文件。
AOF原理
AOF步骤如下:
- Client作为命令的来源,会有多个源头以及源源不断的请求命令。
- 在这些命令到达Redis Server 以后,并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。
- AOF缓冲会根据对应的策略将命令写入磁盘上的AOF文件。
- AOF文件随着写入文件内容的增加,会根据规则进行命令的合并,这里叫做AOF重写,从而起到AOF文件压缩的目的。
- 当Redis Server 服务器重启的时候会从AOF文件载入数据。
这里面有两点需要在详细写: AOF缓冲区同步文件策略 和 AOF重写机制。
AOF的优点和缺点
优点:
- AOF可以更好的保护数据不丢失,AOF有无fsync,每秒fsync和每次写的时候fsync三种策略。默认使用每秒fsync策略,即每隔1秒通过一个后台线程执行一次fsync操作,因此最多丢失1秒钟的数据。
- AOF日志文件过大的时候,可以重写AOF。
缺点:
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 根据所使用的 fsync 策略,AOF的速度可能会慢于RDB。
AOF缓冲区同步文件策略
这里介绍一下AOF缓冲区同步文件的三个策略:
appendfsync always -- always表示每次写入都执行fsync,以保证数据同步到磁盘
appendfsync everysec -- everysec表示每秒执行一次fsync,可能会导致丢失这1s数据
appendfsync no -- no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快
Always策略的同步操作是在主进程的主线程中进行的,由于fsync的阻塞特性,会导致其挂起,在此期间无法服务新的请求,因而吞吐量下降,但确实能够保证内存和硬盘中数据的一致性。
Everysec策略的同步操作是通过后台I/O线程进行的,由于是在子线程中进行,所以主线程并不会被阻塞,可以继续服务新的请求,但是内存和硬盘中的数据会有1秒的差别(不一定精准),这是一种折衷的方案,寻求了一个平衡。
No策略则是将同步操作的控制权交由操作系统,不阻塞主线程,但是数据一致性可能会偏差很大
AOF的日志重写功能
因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。
为了处理这种情况, Redis 支持日志重写: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重写,重写后的文件包含重建当前数据集所需的最少命令。
主从复制时AOF文件如何处理过期
- 为了避免一致性问题,当一个key过期时,DEL操作将被记录在AOF文件并传递到所有相关的slave。即过期删除操作统一在master实例中进行,之后向下传递,而不是各salve各自掌控。这样一来便不会出现数据不一致的情形。
- 当slave连接到master后并不能立即清理已过期的key(需要等待由master传递过来的DEL操作),slave仍需对数据集中的过期状态进行管理维护,当slave当选为master时删除过期keys这一操作会独立执行,然后成为master。
如何选择使用哪种持久化方式
RDB和AOF模式的对比如下:
如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化,但我们并不推荐这种方式:因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份,并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快。
一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性,你应该同时使用两种持久化功能。在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。