缓存是 Redis 最常见的应用之一。缓存能够有效加速应用的读写速度,同时也可以降低后端负载;但也会带来如下问题:数据不一致性、增加代码维护成本和运维成本。

1. 缓存更新策略

1.1 LRU/LFU/FIFO算法删除

使用场景:用于缓存使用量超过了预设的最大值的时候

一致性:清理的数据由算法决定,一致性最差

维护成本:算法不用自己实现,配置即可

1.2 超时删除

使用场景:给缓存数据设置过期时间。若业务可以容忍在一段时间内缓存层数据和存储层数据不一致,那么可以用这种策略

一致性:一段时间内存在一致性问题

维护成本:设置 expire 过期时间即可

1.3 主动更新

使用场景:业务对一致性要求高,真实数据更新后立即更新缓存数据

一致性:一致性最高

维护成本:开发者需要自己完成更新

1.4 最佳实践

  • 低一致性业务建议配置最大内存和淘汰策略的方式使用
  • 高一致性业务结合使用超时删除和主动更新

2. 缓存粒度控制

缓存一条 SQL 记录的全部列,还是部分重要的列,这就是缓存粒度问题

缓存全部数据:通用性高,空间占用大,代码维护简单

缓存部分数据:通用性低、空间占用小、代码维护复杂

3. 缓存穿透

3.1 什么是缓存穿透

缓存穿透是指查询一个不存在的数据,缓存层没有命中则会查询存储层,而存储层查不到这个数据,也就不会写到缓存层。若请求大量的不存在的数据,会导致请求都落到数据库,又由于后端存储数据库不具备高并发性,会导致数据库宕机

3.2 穿透优化

3.2.1 缓存空对象

不存在的数据首次查询存储层没有命中时,将空对象保留到缓存层中,之后这个不存在的数据就会从缓存中获取。且要对这类数据设置一个较短的过期时间,以免浪费内存空间。

3.2.2 布隆过滤器拦截

我们可以通过布隆过滤器非常方便地判断一个给定数据是否存在于海量数据中。

布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在

把所有可能存在的请求的值都存放在布隆过滤器中,当用户请求过来,先判断用户发来的请求的值是否存在于布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端,存在的话才会去请求缓存层。

4. 缓存雪崩

4.1 什么是缓存雪崩

若缓存层由于某些原因不能提供服务(比如缓存在同一时间大面积失效),那么所有请求都会达到存储层,造成数据库短时间内承受大量请求,甚至导致宕机

4.2 雪崩优化

4.2.1 保证缓存层服务高可用性

采用哨兵模式/集群等保证高可用

4.2.2 限流

避免同时处理大量的请求

4.2.3 避免缓存同时大面积失效

随机设置缓存失效时间或者设置缓存永不失效