likes
comments
collection
share

记录redis面试知识点 - 一致性问题、持久化问题、数据过期删除策略、数据淘汰策略

作者站长头像
站长
· 阅读数 11

一致性问题

起因

首先我们知道,redis是工作在内存中的,当我们更新数据库时,我们的redis对应的数据也应该被更新,这时就需要考虑一致性问题。

我们有两种更新redis缓存的办法,第一种是先删缓存后更新数据库,第二种是先更新数据库后删缓存;这两种方式都有一定的问题。

  • 先删缓存,后更新数据库

    假设线程1删除了缓存,此时线程2查询该数据,缓存在查询不到,就回去数据库查询,缓存到redis中并返回,这时线程1更新数据库,就造成了缓存与数据库数据不一致的问题

    例如,先删缓存会导致redis中x=1,而MySQL中x=2,造成数据不一致 记录redis面试知识点 - 一致性问题、持久化问题、数据过期删除策略、数据淘汰策略

  • 先更新数据库,后删缓存(发生几率极小)

    假设缓存中没有该数据(如果有缓存就不会去查询数据库),线程1查询不到缓存数据,会到数据库中查,然而在缓存到redis之前,线程2更新了数据库并且删除缓存(没得删),线程1这时才缓存数据到redis,两者数据就会不一致

记录redis面试知识点 - 一致性问题、持久化问题、数据过期删除策略、数据淘汰策略

解决办法

  • 读写锁

    读读共享,读写互斥,保证数据的强一致性,性能较低

  • 异步写入

    使用MQ发起异步请求,不能保证数据的强一致性,只能保证数据的最终一致性

持久化问题

redis工作在内存中,如果发生宕机,如何将redis恢复到宕机前状态

redis有两者持久化方式:RDB和AOF

  • RDB

    RDB是创建当前redis的副本,作为快照存储到文件中。RDB是默认开启的,在一定时间内修改了足够的次数就会执行bgsave,也可以执行命令bgsave触发;执行命令redis会创建一个子线程,并创建RDB副本保存到磁盘中。

    在保存RDB文件的过程中,如果有数据被修改,redis会在内存中也复制一份副本,所有的修改在这个副本中执行,等到RDB完成后,再将副本中的修改覆盖到redis工作内存中。

记录redis面试知识点 - 一致性问题、持久化问题、数据过期删除策略、数据淘汰策略

  • AOF

    AOF是记录redis所有修改数据的命令,追加新命令到文件中。AOF是默认不开启的,需要执行开启,开启后默认每分钟刷盘。

    在redis中修改的命令是先被记录到缓存中,根据刷盘策略将命令保存到磁盘文件中。保存到缓存再刷盘是为了减少磁盘IO。

    • 刷盘策略

      • 每次修改都刷盘,相当于不使用buffer pool,能保证数据不丢失,但性能较差
      • 每分钟将buffer pool中的命令刷入磁盘,可能会丢失1分钟左右的数据
      • 由系统决定刷盘时机,刷盘时机过于随机,丢失几率大

记录redis面试知识点 - 一致性问题、持久化问题、数据过期删除策略、数据淘汰策略

RDB和AOF的区别

记录方式:RDB记录的是整个redis的快照,AOF记录的是修改的命令

恢复速度:RDB的恢复速度较快,AOF的恢复需要执行所有命令,恢复较慢

恢复完整性:RDB会丢失上次快照之后的所有被修改的数据,AOF完整性取决于刷盘策略

占用大小:RDB占用较小,AOF占用较大

数据过期删除策略

redis可以设置key的过期时间,那么数据过期之后是如何被删除的呢?

惰性删除

惰性删除是指,key超过了过期之后不会立即被删除,而是在下次要使用该key时,先判断是否过期,如果过期就删除该key并从数据库中重新读取

优缺点

  • 缺点:如果一直不使用过期的key,会导致这个key一直占用内存不释放,导致内存浪费

定期删除

定期删除是指,redis会定期扫描设置了过期时间的key,每次只扫描一部分,扫描到过期数据会进行删除

扫描模式

  • SLOW模式:扫描频率10hz,每秒扫描10次,每次扫描耗时不超过25ms
  • FAST模式:扫描频率不确定,但保证两次扫描间隔不超过2ms,每次扫描耗时不超过1ms

优缺点

  • 优点:避免了过期key的内存浪费

数据淘汰策略

redis运行在内存中,如果内存不足,redis如何决定数据的去留?

redis有8种淘汰策略

  • noeviction:默认策略,拒绝新的数据
  • volatile-ttl:对设置了ttl的key,选择ttl最短的key进行淘汰
  • allkeys-random:对所有key,随机淘汰
  • volatile-random:对设置了ttl的key,随机淘汰
  • allkeys-lru:对所有key,使用LRU算法淘汰
  • volatile-lru:对设置了ttl的key,使用LRU算法淘汰
  • allkeys-lfu:对所有key,使用LFU算法淘汰
  • volatile-lfu:对设置了ttl的key,使用LFU算法淘汰

使用建议

如果要保留热点key,建议使用allkeys-lru

扩展

TTL:过期时间

LRU(Least Recently Used):最近最少使用,上次使用时间越久远,越先被淘汰

LFU(Least Frequently Used):最近最少频率使用,使用频率越低,越先被淘汰