浅谈缓存(一)

371 查看

缓存穿透

场景:当通过一个key去数据库查询出来的数据结果为null,缓存系统就不会缓存该数据,每次该key查询都会经过数据库层,造成没有必要的DB开销
解决方案:将该key缓存至缓存系统中,value为一个特殊值(^^,&&...)

缓存失效

场景:由于初始化的时候某些缓存过期时间设置的都一样,一段时间以后缓存全部失效,在这一瞬间的会增大DB的压力
解决方案:在过期时间上加一个随机值;分析用户行为,尽量让失效时间均匀分布

缓存雪崩

场景:key缓存过期失效而新缓存未到期间,该key的查询所有请求都会去查询数据,造成DB压力上升,不必要的DB开销
解决方案:

  1. 加锁排队重建,使请求可以串行化,而不用全部的请求都去查询数据库

  2. 假设key的过期时间是A,创建一个key_sign,它的过期时间比A小,查询key的时候检查key_sign是否已经过期,如果过期则加锁后台起一个线程异步去更新key的值,而实际的缓存没有过期(如果实际缓存已经过期,需要加锁排队重建),但是会浪费双份缓存

  3. 在原有的value中存一个过期值B,BA小,取值的时候根据B判断value是否过期,如果过期,解决方案同上

  4. 牺牲用户体验,当发现缓存中没有对应的数据直接返回失败,并且把需要的数据放入一个分布式队列,后台通过异步线程更新队列中需要更新的缓存

缓存污染

场景:一些非正常操作(导出excel,运营偶发性访问)而导致内存中出现很多冷数据
解决方案:选取合适的缓存算法(LUR-N算法)

缓存首次上线

场景:缓存首次上线,如果网站的访问量很大,所有的请求都经过数据库(如果访问量比较少,可以由用户访问自行缓存)
解决方案:缓存预热,在系统上线之前,所有的缓存都预先加载完毕(增加一个刷新缓存程序,上线后手动刷新或发布时自动调用刷用)

后记

  1. 缓存失效策略:添加key的时候要设置一个过期时间,采用惰性删除和定时删除相结合的策略删除过期键

  2. 多级缓存:线程级->内存级->进程级->文件(静态资源)->分布式(redis)->Db结果.

  3. 二级缓存:二级缓存更多的解决是,缓存穿透与程序的健壮性,当集中式缓存出现问题的时候,我们的应用能够继续运行;一些热点数据做成内存缓存,这些数据是在上线之前是已知的(比如说秒杀,大促商品),通过配置定时任务定时刷新内存缓存,完成和分布式缓存的数据置换;更加自动化的方案,可以根据上游自动发现热点数据,广播消息替换现在集群中内存缓存的数据(但在整个集群中广播,成本比较高,并且二级缓存的管理的成本也很大);

参考资料

缓存穿透、并发和失效,来自一线架构师的解决方案
那些年我们一起追过的缓存写法