[TOC]
# 持久化的方式?
RDB:对内存中数据库状态进行快照 。
AOF:把每条写命令都写入文件,类似mysql的binlog日志。
# RDB和AOF机制
## RDB持久化
### 1. 工作原理:
* Redis调用fork(),产生一个子进程。
* 子进程把数据写到一个临时的RDB文件。
* 当子进程写完新的RDB文件后,把旧的RDB文件替换掉。
### 2. 触发机制
RDB触发持久化分为手动触发和自动触发
1. save 命令(手动触发)
当客户端向Redis server发送save命令请求进行持久化时,由于Redis是用一个主线程来处理所有,save命令会阻塞Redis server处理其他客户端的请求,直到数据同步完成。save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求,因此线上环境不推荐使用
2. bgsave命令(手动触发)
与save命令不同,bgsave是异步执行的,当执行bgsave命令之后,Redis主进程会fork 一个子进程将数据保存到rdb文件中,同步完数据之后,对原有文件进行替换,然后通知主进程表示同步完成。
3. 自动触发
除了手动触发RDB持久化,Redis内部还存在自动触发机制,
在配置中集中配置 save m n 的方式,表示 m秒内数据集存在n次修改时,系统自动触发bgsave 操作。
![](https://img.kancloud.cn/82/3e/823ec14458d462da13c5585e1e874827_633x548.png)
1. Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof(后面会详细介绍该命令)的子进程,如果在执行则bgsave命令直接返回。bgsave/bgrewriteaof 的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题。
2. 父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令
3. 父进程fork后,bgsave命令返回”Background saving started”信息并不再阻塞父进程,并可以响应其他命令
4. 子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
5. 子进程发送信号给父进程表示完成,父进程更新统计信息
### 5\. 数据恢复 & Redis启动加载数据
RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AOF的优先级更高,因此当AOF开启时,Redis会优先载入AOF文件来恢复数据;
只有当AOF关闭时,才会在Redis服务器启动时检测RDB文件,并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止。
所以Redis的内存数据如果很大,会导致数据恢复时间比较长,因此线上实践更倾向于限制单个Redis的内存不能太大,同时结合Redis Cluster集群使用多节点部署
## AOF持久化
### 1.工作原理
由于需要记录Redis的每条写命令,因此AOF不需要触发, AOF的执行流程包括:
* 命令追加(append):将Redis的写命令追加到缓冲区aof\_buf;
* 文件写入(write)和文件同步(sync):根据不同的同步策略将aof\_buf中的内容同步到硬盘;
* 文件重写(rewrite):定期重写AOF文件,达到压缩的目的。
![](https://img.kancloud.cn/00/ce/00ce171ddc52cb69b6f06750f9636acd_588x317.png)
### 2\. AOF 持久化配置
![](https://img.kancloud.cn/24/ab/24ab1e43be4e703ed9fe5ffc49da366a_427x393.png)
### 3\. AOF同步策略
同步步骤分为两步:
* Redis收到写命令后首先会追加到AOF缓冲区aof\_buf,而不是直接写入文件系统,因为AOF缓冲区是内存提存的,写入速度极高,可以避免每次写入命令到硬盘,导致硬盘IO成为Redis的负载瓶颈
* 通过调用系统函数 fsync() 把AOF缓冲区的数据真正写到磁盘里面持久化。由于数据是先存储在缓冲区内存里面,如果碰到断电,宕机那么缓冲区里面的数据没来得急落盘就会丢失,因此我们必须有一个相对可靠的机制保证数据落盘。
Redis写命令写入磁盘的命令是通过appendfsync来配置的。
appendfsync 三个取值代表三种落盘策略:
* `always`:命令写入aof缓冲区后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈。
* `no`:命令写入aof缓冲区后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
* `everysec`:命令写入aof缓冲区后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。
### 4\. AOF文件重写(rewrite)
随着写操作的不断增加,AOF文件会越来越大。例如你递增一个计数器100次,那么最终结果就是数据集里的计数器的值为最终的递增结果,但是AOF文件里却会把这100次操作完整的记录下来。而事实上要恢复这个记录,只需要1个命令就行了,也就是说AOF文件里那100条命令其实可以精简为1条。所以Redis支持这样一个功能:在不中断服务的情况下在后台重建AOF文件。
![](https://img.kancloud.cn/98/84/988402d3e6e46d6b5ac9bae986b1665e_828x532.png)
关于文件重写的流程,有两点需要特别注意:
(1)重写由父进程fork子进程进行;
(2)重写期间Redis执行的写命令,需要追加到新的AOF文件中,为此Redis引入了aof\_rewrite\_buf缓存。
对照上图,文件重写的流程如下:
1. Redis父进程首先判断当前是否存在正在执行 bgsave/bgrewriteaof的子进程,如果存在则bgrewriteaof命令直接返回,如果存在bgsave命令则等bgsave执行完成后再执行。前面曾介绍过,这个主要是基于性能方面的考虑。
2. 父进程执行fork操作创建子进程,这个过程中父进程是阻塞的。
3.1) 父进程fork后,bgrewriteaof命令返回”Background append only file rewrite started”信息并不再阻塞父进程,并可以响应其他命令。Redis的所有写命令依然写入AOF缓冲区,并根据appendfsync策略同步到硬盘,保证原有AOF机制的正确。
3.2) 由于fork操作使用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然在响应命令,因此Redis使用AOF重写缓冲区(图中的aof\_rewrite\_buf)保存这部分数据,防止新AOF文件生成期间丢失这部分数据。也就是说,bgrewriteaof执行期间,Redis的写命令同时追加到aof\_buf和aof\_rewirte\_buf两个缓冲区。
4. 子进程根据内存快照,按照命令合并规则写入到新的AOF文件。
5.1) 子进程写完新的AOF文件后,向父进程发信号,父进程更新统计信息,具体可以通过info persistence查看。
5.2) 父进程把AOF重写缓冲区的数据写入到新的AOF文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致。
5.3) 使用新的AOF文件替换老文件,完成AOF重写。
#### 重写触发:
1. 手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。
2. 自动触发:通过配置`auto-aof-rewrite-percentage`和`auto-aof-rewrite-min-size`来完成
`auto-aof-rewrite-percentage 100`:Redis会记住自从上一次重写后AOF文件的大小(如果自Redis启动后还没重写过,则记住启动时使用的AOF文件的大小)。如果当前的文件大小比起记住的那个大小超过指定的百分比,则会触发重写。
`auto-aof-rewrite-min-size 64mb`:同时需要设置一个文件大小最小值,只有大于这个值文件才会重写,以防文件很小,但是已经达到百分比的情况。
要禁用自动的日志重写功能,我们可以把百分比设置为0:
`auto-aof-rewrite-percentage 0`:禁用日志重写功能
### 5\. 数据恢复 & Redis启动加载数据
前面提到过,当AOF开启时,Redis启动时会优先载入AOF文件来恢复数据;
只有当AOF关闭时,才会载入RDB文件恢复数据。
# AOF和RDB比较
**RDB持久化**
* 优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
* 缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。
**AOF持久化**
* 优点:支持秒级持久化、兼容性好,最多会丢失 1s 的数据。
* 缺点:文件大、恢复速度慢、对性能影响大。
- 消息队列
- 为什么要用消息队列
- 各种消息队列产品的对比
- 消息队列的优缺点
- 如何保证消息队列的高可用
- 如何保证消息不丢失
- 如何保证消息不会重复消费?如何保证消息的幂等性?
- 如何保证消息消费的顺序性?
- 基于MQ的分布式事务实现
- Beanstalk
- PHP
- 函数
- 基础
- 基础函数题
- OOP思想及原则
- MVC生命周期
- PHP7.X新特性
- PHP8新特性
- PHP垃圾回收机制
- php-fpm相关
- 高级
- 设计模式
- 排序算法
- 正则
- OOP代码基础
- PHP运行原理
- zavl
- 网络协议new
- 一面
- TCP和UDP
- 常见状态码和代表的意义以及解决方式
- 网络分层和各层有啥协议
- TCP
- http
- 二面
- TCP2
- DNS
- Mysql
- 锁
- 索引
- 事务
- 高可用?高并发?集群?
- 其他
- 主从复制
- 主从复制数据延迟
- SQL的语⾔分类
- mysqlQuestions
- Redis
- redis-question
- redis为什么那么快
- redis的优缺点
- redis的数据类型和使用场景
- redis的数据持久化
- 过期策略和淘汰机制
- 缓存穿透、缓存击穿、缓存雪崩
- redis的事务
- redis的主从复制
- redis集群架构的理解
- redis的事件模型
- redis的数据类型、编码、数据结构
- Redis连接时的connect与pconnect的区别是什么?
- redis的分布式锁
- 缓存一致性问题
- redis变慢的原因
- 集群情况下,节点较少时数据分布不均匀怎么办?
- redis 和 memcached 的区别?
- 基本算法
- MysqlNew
- 索引new
- 事务new
- 锁new
- 日志new
- 主从复制new
- 树结构
- mysql其他问题
- 删除
- 主从配置
- 五种IO模型
- Kafka
- Nginx
- trait
- genergtor 生成器
- 如何实现手机扫码登录功能
- laravel框架的生命周期