持久化
redis是运行在内存中,所有数据都存储在内存中,内存数据断电就会丢失,因此将数据的更新异步保存到磁盘中。
主流数据库的持久化方式:
1.快照,mysql的Dump和reids的rdb;
2. 写日志,mysql的binlog,redis的aof;
RDB
采用二进制保存,redis启动时可以载入rdb文件进行数据恢复,同时也是复制媒介,例如主从复制。
触发机制
- save(同步命令)
线上环境谨慎使用;
文件策略:生成临时文件,然后新的rdb文件会替换旧文件;
时间复杂度:O(n);
- bgsave(异步命令)
异步命令,不阻塞redis;
执行bgsave命令后会fork出一个子进程去生成RDB文件,但是fork过程是会阻塞redis,fork过程一般情况下非常快;
文件策略与复杂度与save相同;
命令 | save | bgsave |
---|---|---|
IO类型 | 同步 | 异步 |
阻塞? | 是 | 否(但在fork子进程的时候会阻塞) |
复杂度? | O(n) | O(n) |
优点 | 不会消耗额外内存 | 不阻塞客户端命令 |
缺点 | 阻塞客户端命令 | 需要fork,消耗内存 |
- 自动(配置文件可以配置触发条件)
配置文件默认配置:满足任意一个条件,RDB就会触发
配置 | seconds | changes |
---|---|---|
save | 900 | 1 |
save | 300 | 10 |
save | 60 | 10000 |
缺点: 无法控制RDB生成的频率
rdbcompression yes (采用压缩格式)
dbfilename dump-6380.rdb(RDB文件名)
stop-writes-on-bgsave-error yes(发生错误,停止写入)
rdbchecksum yes (在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验)
dir ./ (RDB文件的存储路径)
推荐关闭RDB的save配置进行关闭,关闭自动触发。
- RDB触发机制(我们没有配置触发策略)
(1)全量复制
(2)debug reload(debug级别的重启,不清空内存的重启)
(3)shutdown
RDB总结
- RDB是内存到硬盘的快照
- save会阻塞Redis
- bgsave不会阻塞redis,但是会fork新进程
- save的配置文件的配置,只要满足任意一个配置,就会触发
- 一些特殊的DB触发机制需要特别注意
- 耗时、耗性能,需要将所有数据dump到硬盘,时间复杂度O(n)
- 虽然bgsave不阻塞redis,但是它会fork子进程,消耗内存,虽然使用copy-on-write策略,但是当写入比较大或者内存页比较大也会造成很大的内存消耗。
- 会有很大的IO性能的消耗。
- 依靠配置自动触发, 不可控,容易丢失数据
AOF
原理
对写入的命令刷新到缓冲区,追加AOF日志文件中(根据aof策略刷新到硬盘中),重启后,加载aof文件进行数据恢复。
三种策略
- always 每条命令fsync到硬盘中,保证不丢失数据,IO开销很大。
- everysec 每秒把缓冲区fsync硬盘中,在大写入量的时候可以适当保护硬盘,减少磁盘压力,但是如果发生宕机可能丢失一秒数据。
- no 刷新策略有操作系统决定,不可控。
- 通常我们使用everysec,做一个权衡,一定程度减小硬盘的IO开销,但可能会丢失1秒数据。
AOF与RDB比较:
- RDB是类似二进制文件存储并进行压缩,体积小,而AOF是采用日志的方式保存数据体积大(尽管有AOF重写)。
- AOF的启动优先级比RDB高,所以重新启动会优先选择加载AOF文件。
- RDB是恢复速度快,AOF是日志恢复速度慢。
- RDB需要靠手动save或bgsave或配置触发条件实现,一旦宕机容易丢失数据,而AOF可以选择配置日志的追加策略去控制数据安全性。
- RDB是将数据dump到硬盘,会消耗大量资源,而AOF是采用追加日志的方式保存数据,消耗资源较少(尽管有fork子进程和AOF重写的操作)
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 由我们配置的策略决定 |
轻重 | 轻 | 重 |
最佳策略
RDB默认配置关闭(但在主从复制的时候master还是会执行bgsave将RDB文件传给slave,完成全量复制)
如果集中管理,按照一定周期节点生成RDB文件,做备份还是比较有用的。
AOF建议开启,通常使用everysec,只会丢失1秒数据,如果对数据并不重视,可以关闭,节省开销。
fork
- 同步操作
- 内存量越大,耗时越长(内存页的拷贝)
- latest_fork_usec 上一次执行fork消耗的微秒数
改善fork
- 控制redis实例的最大可用内存:maxmemory
- 降低fork频率,放宽AOF重写自动触发条件,避免不必要的全量复制
子进程开销和优化
- CPU:
(1)开销:RDB和AOF文件生成。属于CPU密集型
(2)优化:不做CPU绑定,不与CPU密集型的服务部署在一起 - 内存:
(1)开销:fork内存开销,但是linux有一个机制copy-on-write(写时复制),父子进程会共享相同的物理内存页,当父进程要写请求的时候创建一个副本,这时候才会消耗额外内存。
(2)优化:在主进程写入较少的时候做bgsave或AOF重写 - 硬盘:
(1)开销:AOF和RDB文件写入
(2)优化:不与高硬盘负载的读物部署在一起;根据写入量选择此安排你类型(SSD);
(3)no-appendfsync-on-rewrite yes在AOF重写时不进行AOF追加操作,可以减少内存开销
AOF追加阻塞(everysec策略)
线程会刷新同步缓冲区,同步线程进行每秒刷盘,同时还会记录最近一次的fsync时间,主线程会比较上次的fsync的时间,如果小于2秒主线程返回,如果超过2秒主线程阻塞。为了保证每秒刷盘的策略,会阻塞直到同步完成。但是主线程不能阻塞,主线程要负责我们的业务处理。
AOF阻塞定位
- 查看redis日志
- info Persistence
会记录发生的次数
- 执行top命令,查看是否发生IO资源金紧张