前言
redis是否真的需要持久化?如果redis中的数据来源是其他数据库或者持久化数据同步而来,个人认为这种情况下没有必要开启持久化
返回正文,redis提供了将数据定期自动持久化至硬盘的能力。redis的持久化有两种,一种是rdb(基于快照),一种是aof(基于非存储非查询操作)
rdb
redis的数据是保存在内存中的,而rdb的实质就是将内存中的数据库状态保存成一个磁盘文件。如下图所示
在这里有2个难点,那就是redis是单线程的,现在要处理持久化,那么就会出现既要处理客户端的请求又要处理持久化,在持久化的过程中数据库状态就会一直在改变,没有一个确定的时刻。这个对持久化而言是致命的,这里redis用了Cory on write 去解决他
另一个难点就是,文件io十分浪费时间的,这对客户端而言十分不友好,所以redis fork了一个子进程去处理他
这里说一下rdb处理的步骤
-
从父进程中fork出一个子进程,子进程处理持久化任务,父进程处理客户端任务,父与子进程共用数据
-
子进程去读取数据库的一部分数据去写入到文件,每次子进程会先从数据库中copy一段数据,这样在写入时就不会受父进程的影响
-
持久化结束后,子进程回收
-
优缺点
- RDB的优点:
1.对性能影响最小。如前文所述,Redis在保存RDB快照时会fork出子进程进行,几乎不影响Redis处理客户端请求的效率。
2.每次快照会生成一个完整的数据快照文件,所以可以辅以其他手段保存多个时间点的快照(例如把每天0点的快照备份至其他存储媒介中),作为非常可靠的灾难恢复手段。
3.使用RDB文件进行数据恢复比使用AOF要快很多。2.RDB的缺点:
1.快照是定期生成的,所以在Redis crash时或多或少会丢失一部分数据。
2.如果数据集非常大且CPU不够强(比如单核CPU),Redis在fork子进程时可能会消耗相对较长的时间,影响Redis对外提供服务的能力。
aof
aof记录的是操作本身,每一次对redis进行非查询操作都会在aof文件中记录一次。所以aof文件会非常庞大(有很没必要的记录),aof分2步,一是aof,二是aof重写(给aof文件瘦身)
-
aof执行步骤
1. 在服务端执行一次非查询操作后,会在aof的缓冲区记录一条
2. 达到配置的时间点,就会刷新缓存(fork子进程,由子进程写入到文件中),配置有三种 -
aof重写步骤
- redis从父进程中fork一个子进程,由子进程进行重写
- 子进程根据数据库状态重写aof文件,这时候父进程照常处理请求,不同的是父进程需要同时往aof缓冲区和aof重写缓冲区写入数据
- 子进程将aof重写文件代替aof文件,并通知父进程
- 父进程收到消息后,将aof重写缓冲区数据刷入新aof文件
3.优缺点 - AOF的优点:
1.最安全,在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用 appendfsync everysec也至多只会丢失1秒的数据。
2.AOF文件在发生断电等问题时也不会损坏,即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复。
3.AOF文件易读,可修改,在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。- AOF的缺点:
1.AOF文件通常比RDB文件更大
2.性能消耗比RDB高
3.数据恢复速度比RDB慢