Redis知识点总结(三)——Redis持久化机制、内存淘汰策略、惰性删除机制
- Redis持久化
- RDB
- AOF
- AOF与RDB的对比
- 混合持久化
- 内存淘汰策略
- 惰性删除机制
Redis持久化
Redis有两种数据持久化的方式,一种是RDB、一种是AOF。
RDB
RDB是内存快照,就是给内存拍一个快照,记录内存当前的数据结构,写入到一个RDB文件中,然后重启时就可以读取这个快照文件进行内存的数据恢复。
Redis有两个命令可以进行RDB持久化,一个是save命令,另一个是bgsave命令。save命令是在当前线程进行RDB持久化,是阻塞当前线程的,一般不用。bgsave则会fork一个子进程进行RDB持久化,在进行持久化的时候,如果主线程发生读写操作修改内存中的数据,会使用COW(copy-on-write)技术,在内存中的数据块被修改前,把将被修改的数据块copy一份副本,让子进程读取副本进行持久化,保证子进程写到RDB文件中的快照数据的一致性。
AOF
AOF是Redis的另一种持久化机制。当开启AOF持久化机制时,Redis每次发生写操作时,除了写内存中的数据结构,还会把写操作的命令,写入到一个AOF文件的内存缓冲区中,然后会按照配置的频率,进行异步的AOF文件刷盘,配置的频率可以是:
- 只写入AOF缓冲区,由操作系统控制刷盘
- 每秒钟刷盘一次
- 每次发生AOF写入,都刷盘一次
当AOF文件过大时,会触发AOF重写机制,对AOF文件进行重写,AOF文件重写可以达到文件瘦身的效果。因为AOF中有很多无效过期的命令,比如对同一个key多次修改,只需记录最后一次的修改命令即可,不需要把前面的命令都记录。
Redis的AOF文件重写机制不是读取AOF文件本身记录的内容进行重写,而是根据当前内存中的数据结构进行重写。
进行AOF重写时,主线程会通过fork函数fork出一个子进程,此时fork函数会拷贝一份主线程的内存副本给子线程。然后子线程会读取内存中的副本数据,生成新的AOF文件。在AOF重写期间,主线程会继续接受并处理客户端发来的请求,当有写请求处理时,会把写请求的命令写一份到AOF重写缓冲区。当子线程生成新的AOF文件后,会把AOF重写缓冲区中的命令往后追加到新的AOF文件中。最后子线程会用新的AOF文件覆盖老的AOF文件。
AOF与RDB的对比
RDB与AOF这两种持久化方式各有优缺点。
RDB模式的持久化方式,重启时数据恢复的速度较快,但是数据不安全,容易丢失数据,在两次RDB持久化期间,Redis宕机,那么在最后一次RDB持久化之后发生的数据修改就全部丢失了。
而AOF持久化方式,如果我们开启每秒钟同步AOF文件到磁盘一次,那么最多就丢失一秒钟数据。但是AOF持久化方式的数据恢复速度较慢,而且会发生频繁的IO操作,当Redis重启时,它是读取AOF文件中的命令重新执行。
如果我们使用Redis仅仅是用作缓存,不追求数据一致性,或者对数据一致性要求不高,可以仅开启RDB持久化,不开启AOF,或者不开启持久化。官网是不建议单独开启AOF的,原因是AOF会带来频繁的IO操作,会影响性能,而且数据恢复速度较慢。如果硬要开启AOF的话,可以使用Redis4.0版本的混合持久化机制。
混合持久化
Redis的混合持久化,就是在AOF持久化的基础上进行的修改。原来的AOF重写是读取内存数据然后写入命令到新的AOF文件,而Redis混合持久化则把AOF重写改为生成一个内存快照,也就是RDB格式的内存快照,再把该内存快照写入重新生成的AOF文件中。两次重写期间的AOF日志,将追加写入到AOF文件中的RDB快照后面。
在启用混合持久化时,Redis重启首先会读取AOF文件中的RDB内存快照,恢复到内存中,然后在读取后面的AOF日志,执行AOF日志记录的命令,应用到内存中。
这样,既可以享受到RDB的快速恢复的好处,又可以通过AOF保证数据丢失相对可控。
内存淘汰策略
Redis在内存被占满时,如果继续收到写请求,需要往内存中写入新的数据,就要进行内存淘汰的操作,把一部分数据淘汰出内存,腾出空间让新的数据写进去。
Redis有多种内存淘汰机制,包括:no-envicition、allkeys-random、volatile-random、allkeys-lru、volatile-lru、allkeys-lfu、volatile-lfu、volatile-ttl。
- no-envicition:不淘汰策略,内存满了,还发生新数据的写入操作,就直接报错。
- allkeys-random:随机的从所有的key中选取一部分进行淘汰。
- volatile-random:在带过期时间的key中随机选取一部分进行淘汰。
- allkeys-lru:使用LRU算法,从所有的key中选取最久未被使用过的一部分key进行淘汰。
- volatile-lru:使用LRU算法,从带过期时间的key中选取最久未被使用过的一部分key进行淘汰。
- allkeys-lfu:使用LFU算法,从所有的key中选取最近最少被使用的一部分key进行淘汰。
- volatile-lfu:使用LFU算法,从带过期时间的key中选取最近最少被使用的一部分key进行淘汰。
- volatile-ttl:从带过期时间的key中选取最快到期的一部分key进行淘汰。
惰性删除机制
Redis中过期键的删除不是立即删除,而是惰性删除。惰性删除一方面会定时的随机抽取一部分key检查是否过期,一方面是当查询某个key发现它过期时,会顺便删除,然后返回空值。