Redis持久化
Redis持久化
1. AOF日志
1.1 AOF日志
在Redis执行完一条命令后,将该命令记录到AOF日志中
为什么是在执行完命令之后记录日志呢?
- 避免额外的检查开销,AOF 记录日志不会对命令进行语法检查;
- 在命令执行完之后再记录,不会阻塞当前的命令执行。
这样也带来了风险:
- 如果刚执行完命令 Redis 就宕机会导致对应的修改丢失;
- 可能会阻塞后续其他命令的执行(AOF 记录日志是在 Redis 主线程中进行的)。
1.2 写入操作
如果直接将命令写回到磁盘中的AOF文件中,会出现如下问题:
- 还没写会磁盘就宕机,数据丢失
- 阻塞下一条Redis命令执行(Redis单线程)
因此,Redis会将命令先写到一个叫**“AOF缓冲区”**的地方,write()
系统调用将AOF缓冲区数据写到内核缓冲区PageCache,再由内核决定什么时候将数据写回磁盘:
- Always:每次写命令执行完就将记录写回磁盘
- EverySec:每次Redis写命令执行完放到PageCache,由内核每隔一秒写入磁盘
- No:由内核自己决定什么时候写入磁盘
1.3 AOF重写
AOF文件会越来越大,超过一定阈值启用重写机制来压缩AOF文件
对每条键值对数据,用一条日志记录它们的最新状态(因为一条键值对数据可能经过多次更改,原AOF日志文件里有多条关于它们的冗余数据),以达到压缩AOF文件的目的。
这个过程是在一个后台的子进程中进行的,也就是此时主进程仍可以执行写操作,在这个过程中执行的写操作命令不仅要加到AOF缓冲区中,还要加到一个叫**“AOF重写缓冲区”**的地方,用于让重写后新的AOF文件知道在它重写过程中又多了什么写操作,记录下后覆盖老的AOF文件,实现压缩。
2. RDB快照
2.1 RDB快照
相较于AOF日志记录的是一条条的命令,RDB快照直接记录某一个瞬间的所有数据。
两者相比,在Redis重启时,RDB快照的持久化方式加载速度更加快,不用像AOF日志那样一条一条执行命令。
2.2 RDB快照记录
bgsave
使用一个子进程去对当前的数据做快照,如果这个过程中主进程中的都是读操作则没有影响;若主进程发生了写操作,则会发生写时复制,会将被修改的数据复制一份,主进程在这个新生成的副本上做修改,子进程继续对原数据做快照。
极端情况下,所有数据都被修改,所有数据都要被复制,导致内存占用增大
也就是说,在做RDB快照过程中发生的写操作只能等到下一次RDB才能被同步到磁盘中,这就导致了数据丢失的风险。
3. 混合持久化
综上所述,使用AOF日志虽然慢,但是没有数据丢失风险;而使用RDB快照虽然快,但是会有增量数据丢失的风险。于是有混合持久化AOF+RDB的方式:
重写AOF日志时,将数据以RDB的形式写入到AOF日志中,写完再去AOF重写缓冲区中,把记录RDB时新生成的AOF记录写到新的AOF日志中,于是新的AOF日志里既有RDB格式(前),又有AOF格式(后)。
既快,又不怕增量数据丢失