- 【学习笔记】Redis的持久化
- 前言
- 持久化简介
- RDB
- save
- bgsave
- AOF(Append-Only File)
- AOF重写
- AOF相关问题
- RDB于AOF对比
- 混合持久化
持久化简介
持久化(Persistence):即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。
在Redis中有RBD和AOF两种持久化方式,但是一般默认RDB。
RDB默认中Redis中是先把内存数据库快照保存在名字为dump.rdb的二进制文件中。
save我们能通过save来配置持久化策略。
save N M #让redis在“N秒内至少有M个改动”才会触发一次rdb持久化操作。 #例如: save 100 60 #表示在100秒内有60个改动
当执行save命令时,Redis同步做快照操作,在快照执行过程中会阻塞所有来自客户端的请求。当redis内存中的数据较多时,通过该命令将导致Redis较长时间的不响应。所以不建议在生产环境上使用这个命令,而是推荐使用bgsave命令。
bgsaveRedis借助了linux系统的写时复制(Copy-On-Write)技术,在生成快照的同时,仍然可以接收命令处理数据。简单来说,bgsave线程是由主线程fork生成的子线程,可以共享主线程所有的内存数据。bgsave线程运行后,开始读取主线程的内存数据,也就是redis的内存数据,将内存数据写入到dump.rdb文件中。此时,如果主线程处理的命令都是读操作,则bgsave线程不受影响。如果主线程处理了写操作,则会对该命令操作的数据复制一份,生成副本,bgsave线程会把这个副本写入到dump.rdb文件中,而在这个过程中,主线程仍可执行命令。
和save的对比:
save | bgsave | |
---|---|---|
IO类型 | 同步 | 异步 |
是否阻塞其他命令 | 是 | 否 |
复杂度 | O(n) | O(n) |
优点 | 不消耗额外内存 | 不阻塞操作 |
缺点 | 阻塞操作 | 消耗额外内存 |
RDB的优点:
- 因为dump.rdb是二进制文件,当发生灾难级别的数据丢失,使用二进制文件则可以很容易的进行恢复。
- 生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
- RDB 在恢复大数据集时的速度比AOF的恢复速度要快。
RDB的缺点:
- RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,频繁执行成本过高。
- 在一定间隔时间做一次备份,所以如果redis意外down掉的话,最后一次快照之后的修改数据会被丢失(数据有丢失)。
AOF(Append-Only File)
Redis 默认不开启。AOF采用日志的形式来记录每个写操作,并追加到文件中。开启后,执行更改Redis数据的命令时,就会把命令写入到AOF文件中。
Redis 重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复工作。
手动配置:
# appendonly yes
AOF可以配置三种刷盘策略:
appendfsync always:每次执行写命令都会刷盘,非常慢,也非常安全。 appendfsync everysec:每秒刷盘一次,兼顾性能和安全。 appendfsync no:将刷盘操作交给系统,很快,不安全。AOF重写
随着时间的推移,AOF备份文件会越来越大!这样不仅导致占据大量的磁盘空间,也会使一些移动复制,加载分析显得非常耗时!
为了减少文件增加,可以采用 压缩 的方式来进行一个文件内存的缩小。
如下两个配置可以控制aop文件重写的频率:
# auto‐aof‐rewrite‐min‐size 64mb: -- aof文件至少达到了64m才会触发重写 # auto‐aof‐rewrite‐percentage 100: -- 距离上次重写增长了100%才会再次触发重写
AOF也可以手动触发重写:bgrewriteof
注意,AOF重写redis会fork出一个子进程去做(与bgsave命令类似),不会对redis正常命令处理有太多影响
重写的流程:
- 主进程会fork一个子进程出来进行AOF重写,并不是对原文件进行重新整理,而是直接读取redis服务内存中现有的键值对,然后用一条命令去代替每个键值对,写入到新的AOF文件中
- 在fork子进程这个过程中,服务端仍然可以对外提供服务,在子进程重写的这个时间段里面,,主进程的数据更新操作,会缓存到aof_rewrite_buf中,也就是单独开辟一块缓存来存储重写期间收到的命令,当子进程重写完以后再把缓存中的数据追加到新的aof文件。
- 当所有的数据全部追加到新的aof文件中后,会把旧的aof文件替换成新的aof文件,此后所有的操作都会被写入新的aof文件。
- 如果在rewrite过程中出现故障,不会影响原来aof文件的正常工作,只有当rewrite完成后才会切换文件。因此这个rewrite过程是比较可靠的。
在aof_buf缓存到旧的aof文件中间其实还有一个子进程,将aof_buf缓存中的数据同步到aof文件中取。
AOF相关问题问题1:数据都是实时持久化到磁盘吗?
虽然每次执行更改Redis数据库内容的操作时,AOF都会将命令记录在AOF文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了aof_buf缓存中。在默认情况下系统每30秒会执行一次同步操作。以便将aof_buf缓存中的内容真正地写入磁盘中。
在这30秒的过程中如果系统异常退出则会导致aof_buf缓存中的数据丢失。这个时候就需要Redis在写入AOF文件后主动要求系统将aof_buf缓存内容同步到磁盘中。在redis.conf中通过如下配置来设置同步机制。
fork()出一个子进程,通过子进程将aof_buf缓存中的数据同步到磁盘中:
问题2:为什么要AOF重写?
RDB于AOF对比比如我有业务很简单,就来回delete set同一个key。就这个业务运行了10年,那么aof文件将记录无数个delete k1, set k1。其实都是重复的,但是我aof每次都追加,文件变成了1T大小。这时候Redis宕机了,要恢复,你想想1TB大小的aof文件去恢复,累死了。最主要的是1TB大小只记录了两个命令,所以压缩其实就是来处理这件事的。
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 容易丢失数据 | 根据策略决定 |
如果我们采用 RDB 持久化会丢失一段时间数据。如果我们采用 AOF 持久化,AOF日志较大,重放比较慢。
Redis 4.0 为了解决这个问题,支持混合持久化。将 RDB 文件的内容和增量的 AOF 日志文件存在一起。
混合持久化同样也是通过 bgrewriteaof 完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以 RDB 方式写入 AOF 文件,然后在将重写缓冲区的增量命令以 AOF 方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据。
于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。
参考文章链接:
文章1 |
---|
文章2 |
文章3 |