文章目录

  • 缓存穿透、缓存击穿、缓存雪崩
  • Redis键的过期
    • 1. 设置过期时间的命令
    • 2. 过期时间设置原则
    • 3. Redis处理过期键策略
    • 4. Redis缓存淘汰策略
  • Redis的线程
    • 1. 版本变更中的多线程
    • 2. Redis为什么快
    • 3. Redis核心为什么使用单线程
  • 如何设计分布式锁
  • 双写一致问题
    • 1. 删除和更新缓存的比较
    • 2. 先删缓存后更数据库
    • 3. 先更新缓存后更新数据库
    • 4. 先更数据库,后删除/更新缓存
    • 5. 延时双删
    • 6. 如何强一致
  • Redis高可用
    • 1. 哨兵
    • 2. 集群
    • 3. 复制/主从同步
  • 如何使用布隆过滤器
  • 其它
    • 1. Redis各种数据结构原理
    • 2. 持久化
  • 参考

缓存穿透、缓存击穿、缓存雪崩

缓存穿透缓存击穿缓存雪崩
描述查询不存在的数据某小段时间大量相同查询达到存储层缓存无法提供服务,大量请求打到存储层
可能原因1. 缓存和库中数据被删除
2. 恶意攻击
某些热点数据过期失效大量数据过期,或Redis宕机
解决方法1. 缓存空对象,未命中时将空值存入缓存
2. 布隆过滤器拦截
1. 热点数据永不过期
2. 互斥加锁,多线程访问redis某key无数据时,只有一个线程能去存储层查询并存入redis,然后其它线程再从redis取数据
1. 避免数据同时过期,设置过期时间为随机值
2. 降级和熔断,对于非核心请求直接返回预定义信息
3. 构建高可用服务

Redis键的过期

1. 设置过期时间的命令

命令示例和描述
PERSISTPERSIST key-name —— 移除键的过期时间
TTLTTL key-name —— 查看给定键距离过期还有多少秒
EXPIREEXPIRE key-name seconds —— 让给定键在指定的秒数之后过期
EXPIREATEXPIREAT key-name timestamp —— 将给定键的过期时间设置为给定的 UNIX 时间戳
PTTLPTTL key-name —— 查看给定键距离过期时间还有多少毫秒
PEXPIREPEXPIRE key-name milliseconds —— 让给定键在指定的毫秒数之后过期
PEXPIREATPEXPIREAT key-name timestamp-milliseconds —— 将一个毫秒级别精度的 UNIX 时间戳设置为过期时间

2. 过期时间设置原则

  • 热点数据不设置过期时间,可以避免缓存击穿问题
  • 设置的过期时间时随机值,避免大量key同时过期,导致缓存雪崩

3. Redis处理过期键策略

  • 惰性删除: 客户端访问key时,检查是否过期,过期则删除
  • 定期删除: 服务端将设置了过期时间的key放到独立字典中,定期进行扫描。扫描逻辑:
    • 随机选择部分key(20)
    • 删除过期key
    • 若过期比例超过25%则重复操作

4. Redis缓存淘汰策略

LRU和LFU的算法代码见这里
当写入数据将导致超出maxmemory限制时,Redis会采用maxmemory-policy所指定的策略进行数据淘汰。该策略包含如下八种。

策略描述版本
noeviction直接返回错误;
volatile-ttl从设置了过期时间的键中,选择过期时间最小的键,进行淘汰;
volatile-random从设置了过期时间的键中,随机选择键,进行淘汰;
volatile-lru从设置了过期时间的键中,使用LRU算法选择键,进行淘汰;
volatile-lfu从设置了过期时间的键中,使用LFU算法选择键,进行淘汰;4.0
allleys-random从所有的键中,随机选择键,进行淘汰;
allkeys-lru从所有的键中,使用LRU算法选择键,进行淘汰;
allkeys-lfu从所有的键中,使用LFU算法选择键,进行淘汰;4.0

前缀含义:

  • volatile:从设置了过期时间的键中淘汰数据
  • allkeys:从所有的键中淘汰数据

LRU与LFU:

  • LRU最近最少访问删除策略,非热点数据在偶尔访问后,一段时间内不会被淘汰。
  • LFU最近最不经常使用删除策略,访问次数最少会被删除,如果多个数据访问数据相同,则这些数据根据LRU策略删除

Redis的线程

从 Redis 的 v1.0 到 v6.0 版本之前,Redis 的核心网络模型一直是一个典型的单 Reactor 模型。Redis v6.0 才改造成多线程模式。

Redis的主要瓶颈是内存和网络带宽,而非CPU。6.0引入多线程解决网络IO问题。

1. 版本变更中的多线程

涉及的多线程
Redis 3.0前1. 持久化:BGSAVE和BGREWRITEAOF会fork子进程进行
2. 异步任务:关闭文件、将缓冲区冲洗到磁盘文件中
Redis 4.0异步删除键值对的命令:UNLINK(DEL的异步版本)、FLUSHALL ASYNC、FLUSHDB ASYNC(删除选项,整个数据集还是单个数据库)
Redis 6.0socket读写、请求解析是多线程,但命令执行是单线程(键值对操作,防止线程不安全)

2. Redis为什么快

  • 单线程处理命令避免上下文切换和线程竞争带来的开销
  • 数据存储在内存
  • c语言本身性能高
  • IO多路复用技术,实现高吞吐的网络IO UNIX IO五种模型

3. Redis核心为什么使用单线程

  • 避免上下文切换
  • 避免同步机制带来开销
  • 简单可维护

如何设计分布式锁

  • set key value nx ex seconds 原子性地赋值和设置过期时间
  • Redisson框架

更多

双写一致问题

  • 先删缓存后更数据库
  • 先更新缓存后更新数据库
  • 先更数据库后删缓存
  • 先更新数据库后更新缓存
  • 延时双删

1. 删除和更新缓存的比较

  • 删除:
    • 优点:操作简单
    • 缺点:下次读取时需要重新从数据库取
  • 更新:
    • 优点:数据变化更新及时
    • 缺点:写多读少的场景性能差。

2. 先删缓存后更数据库


在A线程删缓存和更新数据库期间,其他线程查询并更新缓存后,会造成数据库和缓存不一致的情况。

3. 先更新缓存后更新数据库

A线程更新缓存后若数据库更新失败,会造成数据库和缓存不一致的情况。一般需要重试,一般通过异步方式进行

4. 先更数据库,后删除/更新缓存

  • 在 A线程更新数据库到删除/更新缓存期间,其它线程查询到的数据是历史缓存数据,与数据库不一致。
  • 若A线程删/更新缓存失败,则从A更新数据库后,缓存和数据库就一直不一致。

5. 延时双删

  1. 若B线程在A第一次删缓存和更数据库期间查询数据库,并在A更新数据和延时删除缓存之间更新了缓存,那么在B更新缓存和A延时删缓存的中间时刻发生数据不一致。
  2. 若是B线程更新缓存在A延时删除缓存之后发生,则同样发生了数据不一致。这说明延时时间设置不合理。

延时时间的设置:

  • 设置时间过大可能导致情况1发生
  • 设置时间过小可能导致情况2发生
  • 需要根据业务场景合理估计设置时间

6. 如何强一致

  • 对单key使用分布式锁,将缓存操作和数据库操作放到一个锁中,会影响性能,需要注意失败处理和锁的释放
  • 放弃缓存
  • 单key串行化读写,相同key的操作加入等待队列(类似于加锁)

Redis高可用

1. 哨兵

角色说明:

  • 主结点:负责处理外部的读写操作
  • 从结点:只读,主节点无效时可能被选拔为主节点
  • 哨兵:监控主结点、从结点、其他哨兵。主结点故障时选从结点变为主结点。哨兵是特殊的Redis结点,不存储数据,只只支持部分命令

2. 集群

通过虚拟槽实现数据分片。

3. 复制/主从同步

psync命令支持全量复制和部分复制。

全量复制的两个阶段:

  • 同步阶段:主结点执行BGSAVE,将RDB通过网络传输给从结点,从结点载入数据。实现数据一致
  • 命令传播:数据一致后,主节点数据发生更改,会将使数据发生更改的写命令发送给从结点,进而一致
    部分复制的来由:
    若每次主从结点网络断开重连后都需要全量复制,不必要资源开销较大。可以从上次复制过的数据开始增量更新
    部分复制实现的方式:
  • 复制偏移量:主从结点记录上次复制后的偏移量,下次可以接着该位置增量更新
  • 积压缓冲区:写命令会被记录到增量缓冲区,增量复制时回到缓冲区找偏移量。找到则将偏移量开始后的数据传递给从结点。若是找不到说明相差太多,需要进行全量复制。
  • 主节点运行ID:为了防止从结点切换复制的主节点,从结点需要记录之前同步的主节点ID,每次想要部分复制时比较当前存储的ID和想要复制的主节点ID是否相同。

如何使用布隆过滤器

布隆过滤器使用bit位存储数据。占用空间小。

可以用于拦截不存在的数据,有概率拦截到存在的数据。

其它

1. Redis各种数据结构原理

见【Redis】数据结构与对象

2. 持久化

见【Redis】RDB与AOF持久化

参考

  • Java面试宝典
  • Redis多线程网络模型全面揭秘
  • Reactor模式介绍
  • Redis(十三):Redis多线程
  • Redis6系列1-线程模型(单线程OR多线程)
  • Redis6.0多线程模型总结
  • redis缓存为什么要延时双删
  • 分布式锁中的王者方案 - Redisson
  • 七种方案!探讨Redis分布式锁的正确使用姿势

更多推荐

【Redis】八股文必背