作为开发中最常用的缓存、NOSQL数据库,常常会和MySQL这个关系型数据库一起使用,对比发现:
1.MySQL可以保证事务中的持久性,即只要事务提交,之后无论MySQL挂了还是服务器宕机,数据都不会丢失。
2.而Redis虽然也有持久化策略,但是它缺无法保证持久性,当Redis挂了,往往都会丢失一定的数据。
造成这两种的区别就是它们的持久化策略不同:
1.MySQL的持久化保障是redo log日志:MySQL的redo log-优快云博客
2.Redis的持久化策略有:
- RDB(Redis Database Backup)持久化
- AOF(Append-Only File)持久化
- 混合持久化(RDB + AOF):Redis 4.0 引入了一种将 RDB 和 AOF 结合的持久化方式。
RDB 持久化
RDB(Redis Database)持久化是 Redis 在指定时间间隔内创建数据快照,并将快照保存在磁盘上。RDB 持久化的核心是将内存中的数据通过序列化的方式保存为二进制文件(.rdb
文件)。
操作过程
- Redis 会在后台创建一个子进程进行 RDB 快照操作。(bgsave指令)
- 在执行时,Redis 会将当前内存中的数据写入到一个新的 RDB 文件中(生成新文件,而不是覆盖现有的 RDB 文件)。
- 在配置中可以设置定期保存快照的策略,典型的配置是
save <seconds> <changes>
,例如save 900 1
表示每 900 秒(15 分钟)至少有一个键发生变化就 保存一次 RDB 文件。
优缺点
- 优点:
- 性能好:RDB 是基于全量快照的方式,操作非常高效,并且对 Redis 主进程的影响较小。
- 适合备份和迁移:RDB 文件是一个单一的文件,方便进行备份、恢复和数据迁移。
- 崩溃恢复快:RDB 文件是完整数据,而AOF是指令。
- 缺点:
- 持久化不完全:因为 RDB 持久化是周期性的快照,无法保证在快照之间的数据丢失。比如,如果 Redis 在保存快照的时间窗口内崩溃,那么这个时间窗口内的所有数据都会丢失。
AOF 持久化
AOF(Append-Only File)持久化将 Redis 操作记录到一个追加的日志文件中。每个修改操作都会以 Redis 命令的形式追加到 AOF 文件末尾。通过重放 AOF 文件中的命令,Redis 可以重新执行这些操作,恢复到崩溃前的状态。
操作过程
- 每当 Redis 执行一个写命令时(例如
SET
、DEL
等),它都会将该命令写入 AOF 文件。 - Redis 会定期将 AOF 文件中的命令刷新到磁盘上,确保数据持久化。
- AOF 有三种刷盘策略:(与MySQL的redolog的持久化很像)
- 每次写入后立即刷盘(
always
):每个写命令都会立即同步到磁盘,最安全但最慢。调用write(写道操作系统的缓存空间)后立刻调用fsync(写入磁盘) - 每秒刷盘一次(
everysec
):每秒钟将数据同步到磁盘,性能和安全性之间的折中。调用write(写道操作系统的缓存空间)后马上返回,每秒调用fsync(写入磁盘) - 从不刷盘(
no
):不自动同步,由操作系统缓存控制,性能最佳,但最不安全。调用write(写道操作系统的缓存空间)后返回,操作系统决定什么时候调用fsync(写入磁盘)(Linux一般是30s一次)。
- 每次写入后立即刷盘(
优缺点
-
优点:
- 持久性高:AOF 记录了所有的操作,数据丢失较少,甚至在网络断开、系统崩溃时,也能恢复最近的操作。
- 灵活性高:AOF 可以通过
BGREWRITEAOF
命令压缩 AOF 文件,去除冗余命令,提高文件大小和恢复效率。
-
缺点:
- 性能开销:每次操作都要写 AOF 文件,尤其是配置为
always
模式时,会对性能产生较大的影响。 - 文件较大:相比 RDB,AOF 文件会持续增长,且需要进行定期重写(
BGREWRITEAOF
),否则会导致 AOF 文件不断增大。
- 性能开销:每次操作都要写 AOF 文件,尤其是配置为
混合持久化(RDB + AOF)(推荐)
Redis 从 4.0 版本开始支持混合持久化策略。它结合了 RDB 和 AOF 的优点,在写 AOF 文件的同时生成 RDB 快照。
混合持久化的特点:
- Redis 先生成 RDB 快照,然后将 AOF 操作追加到文件末尾。(导致文件可读性降低)
- 适合高性能要求,因为它结合了 RDB 的快速恢复和 AOF 的高可靠性。
- 使用
appendonly yes
和save
配置项可以启用混合持久化。
为什么 MySQL 能保证持久性,而 Redis 不能保证
MySQL中的innodb_flush_log_at_trx_commit
参数,它决定了redolog的刷盘策略,在默认为1的情况下每次事务提交时,都会将 redo log 刷写到磁盘,这能保证事务的强持久性,但会影响性能。因此只要事务提交了,redo log日志就一定到了磁盘。
而Redis的RDB肯定没法保证,因为RDB执行save的间隔太大了,中间只要宕机就会丢失之间的所有命令。而即使是使用AOF的每次写入后立即刷盘(always
)(性能很差,推荐使用每秒刷盘一次(everysec
))也不能保证,如图:
Redis 的主要目标是性能,保证低延迟和高吞吐量。为了达到这些目标,Redis 在持久化和恢复上做了折衷,他的持久化在命令执行后执行(1.需要执行命令来判断指令是否合法,2.防止阻塞主线程)。
如果刚刚执行完命令就宕机就会(Always策略)丢失一条命令,因此其持久化策略不如 MySQL 那样具有强一致性。