对于缓存而言,

  1. 约束好key的规范,合理确定Val值的大小。(生产实际案例:redis做缓存,因Val值过大的key太多,在reids的性能出现了问题,造成业务不可用
  2. 合理分配缓存失效时间
  3. 合理加锁控制单线程DB查询写缓存操作

缓存穿透

程序在处理缓存时,一般是先从缓存查询,如果缓存没有这个key获取为null,则会从DB中查询,并设置到缓存中去。

按这种做法,那查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。

解决办法

  1. 最好对于每一个缓存key都有一定的规范约束,这样在程序中对不符合parttern的key 的请求可以拒绝。
  2. 如果对应在数据库中的数据都不存在,我们将此key对应的value设置为一个默认的值,比如“NULL”,并设置一个缓存的失效时间。当然这个key的时效比正常的时效要小的多
  3. 还有一种,将可能出现的key值以hash形式存储在一个很大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力

缓存雪崩

指的是大量缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

解决办法

  1. 这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布,设置不同的过期时间。至于缓存永不过期,个人建议慎重使用。
  2. 用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。在加锁方法内先从缓存中再获取一次,没有再查DB。 (当然也可以: 在没有获取锁的线程中一直轮询缓存,至超限时)

缓存击穿

指的是热点key在某个特殊的场景时间内恰好失效了,恰好有大量并发请求过来了,造成DB压力。

解决办法

与缓存雪崩的解决方法类似: 用加锁或者队列的方式保证缓存的单线程(进程)写,在加锁方法内先从缓存中再获取一次,没有再查DB。 

02-20 00:35