目录
一、单点 Redis 存在问题
- 数据丢失:基于内存存储,服务器宕机 / 重启导致数据丢失
- 并发能力:Redis 并发虽然高但是有些场景还是不够高,比如双十一秒杀、抢票等
- 故障恢复:单台 Redis 故障之后导致服务不可用,要保证高可用,需要 Redis 自动故障恢复,在服务运行的过程中修复出故障的节点
- 存储能力:内存容量有限,单台 Redis 内存容量难以满足需求
接下来分四个章节分别讨论上述四个问题的解决方案:Redis 持久化(本章)、主从机制、哨兵机制以及分片集群
二、RDB 持久化
1、RDB:Redis Database Backup file Redis 数据备份文件 / RDB 快照,将内存中的数据写入磁盘
2、快照文件称为 RDB 文件,默认保存在 当前运行目录
redis.conf 中有一个配置,配置了 RDB 文件默认保存的位置
dir ./
表示当前目录dbfilename dump.rdb
表示 RDB 文件名称rdbcompression yes
表示是否压缩,建议不开启,压缩会消耗 CPU,不压缩消耗磁盘没关系
3、如何开启 RDB?
- 连接 Redis 之后执行 save 命令,但是 save 是由 Redis 的主进程来执行 RDB 的,会阻塞命令的执行
- 后台进程执行 RDB:bgsave,开启子进程执行 RDB,避免主进程受到影响
4、RDB 的执行频率
- 停机时 自动执行 RDB,保存在当前目录
Saving the final RDB snapshot before exiting.
运行中突然宕机不会做 RDB,需要每隔一段时间进行一次 RDB
- 配置:保存在 redis.conf 文件中
- save 900 1:900 秒内至少有 1 个 key 被修改,则执行 bgsave,如果是
save ""
则表示禁用 RDB - save 60 1000
- save 300 10
- save 900 1:900 秒内至少有 1 个 key 被修改,则执行 bgsave,如果是
秒数相同,修改次数越大,执行频率越低
修改次数相同,秒数越大,执行频率越低
100 秒内至少修改 10 次和 200 秒内至少修改 20 次有什么区别❓
虽然平均都是两秒一次,但是判断的时间范围不同,时间范围越大,对执行 RDB 的限制越宽容
save 10 1000:如果一直都没有 10 秒内修改 1000 次,那就一直不会执行 bgsave 吗❓所以需要配适当的时间间隔?
5、执行频率怎么配?
- 太长:有可能丢失很多数据
- 太短:数据量大时,频繁 RDB 性能不好
- 默认:30s / 60s,但是还是有可能丢失数据=>AOF
6、RDB 底层原理 ✨✨✨
- bgsave 开始时 主进程会 fork 一个后台的子进程(子进程共享主进程的内存数据),完成 fork 后由子进程读取内存数据并写入 RDB 文文件
- 子进程共享内存:fork 子进程时会复制主进程的页表(保存了虚拟内存和物理内存的映射关系),读取数据时通过页表映射到相同的物理内存进行读取
- 读写冲突:主进程异步执行 RDB,在子进程执行 RDB 的过程中,主进程还是可以接受客户端的请求来修改内存中的数据,造成父子进程数据不一致
- 写时复制技术(Copy on Write):将共享内存设置为只读 read-only 的,如果父子进程任一方想要修改数据,就会进行数据拷贝,将要修改的数据拷贝一份副本,修改副本,子进程执行 RDB 读取的还是修改前的数据,主进程读取的则是修改之后的数据(页表映射改变了)
- 极端情况:RDB 过程中,主进程把所有数据都改了一遍,则所有的共享数据都被拷贝了一份新的,Redis 对内存的占用翻倍==>RDB 前要预留一部分空间来做 RDB,否则会造成内存溢出
在此过程中主进程几乎是零阻塞的,只在 fork 子进程时阻塞一小段时间,后面的工作都有子进程去执行,所以对主进程没什么影响
7、RDB 方式 bgsave 的执行流程
- fork 子进程,共享内存空间
- 子进程读取内存数据,写入 RDB
- 子进程读取完成,用新的 RDB 文件替换旧的 RDB 文件
8、写时复制出来修改的数据什么时候 RDB❓是在下一次 RDB 的时候才能得到持久化吗
9、RDB 的优缺点
- 每次 RDB 间隔可能 导致数据丢失,存在数据安全的漏洞
减少 RDB 执行间隔?❌ 耗时⬇️
- 耗时较长:fork、压缩、写出 RDB 文件都是比较耗时的操作
三、AOF 持久化
提高数据安全性,弥补 RDB 的缺陷
1、AOF:Append Only File 追加文件。记录 Redis 处理的 写命令,命令日志文件
2、AOF 文件格式 / 内容
- *2:后面命令的长度
- $6:字符个数
- select 0:选择 0 号库
3、数据恢复:重启 Redis 服务器时读取 AOF 文件,将文件里的命令重新执行一遍
-
相对于 RDB 直接写入数据而言,AOF 要先执行命令,效率更低
4、如何开启:修改 redis.conf 配置文件来开启 AOF appednonly yes
appendfilename "appendonly.aof"
5、开启频率
- appendfsync always:每次执行一条写命令,就立即记录到 AOF 文件(磁盘文件)中,数据安全最有保障,但是性能最差
执行命令和写入 AOF 文件都是由 主进程来完成 的
- appendfsync everysec:默认方案,执行完写命令,先放入 AOF 缓冲区(写内存),每隔一秒再将缓冲区的数据写入 AOF 文件,有可能丢失 1 秒中的数据,性能和安全性都可以
- appendfsync no:执行完写命令先放入 AOF 缓冲区,由操作系统来决定 何时写入 AOF 文件,有可能丢失很多的数据,无法预知,不安全但是性能好
为什么先执行命令再写入文件?
执行成功后代表命令是有效的,这样写入文件的命令都是可以执行的命令,不需要额外再做校验,恢复数据时读取 AOF 文件中的命令也不会出错
6、缺点
- 记录冗余命令占用 AOF 文件空间,AOF 是追加 操作 命令,对同一个 key 的多次读写都会被记录下来,RDB 记录的是 新值 以覆盖旧值
- 重启时重复执行对同一个 key 的操作,浪费资源
7、AOF 重写✨
- 解决:AOF 文件过大的问题,记录了对同一个 key 的多次写操作,但是只要记录最后一次写操作就好了
- 实现:执行 bgrewriteaof 命令(Redis 在后台开启了独立子进程执行 AOF 重写操作),执行 AOF 重写,减少了不必要 / 没意义的冗余命令
- 重写时机:在 redis.conf 中配置
- auto-aof-rewrite-min-size 64mb:AOF 文件体积达到 64mb 就开始重写
- auto-aof-rewrite-percentage 100:AOF 文件比上次的 AOF 文件增长超过了 100% 就触发重写(上次指的是❓上一次重写 AOF 的文件大小吗,那就是翻倍就重写)
四、混合持久化
AOF 和 RDB 各有优缺点,Redis 现在采用的是混合持久化,即 RDB 和 AOF 混合使用(先 RDB 写入 AOF 文件,后面的增量命令直接以 AOF 追加到 AOF 文件中)
1、AOF 和 RDB 的对比