对缓存击穿的一点思考

前言

缓存(内存 or Memcached or Redis.....)在互联网项目中普遍应用,本篇博客将讨论下缓存击穿这一个话题,涵盖缓存击穿的现象、解决的思路、以及经过代码抽象方式来处理缓存击穿。缓存

什么是缓存击穿?

对缓存击穿的一点思考

上面的代码,是一个典型的写法:当查询的时候,先从Redis集群中取,若是没有,那么再从DB中查询并设置到Redis集群中。数据结构

注意,在实际开发中,咱们通常在缓存中,存储的数据结构是JSON。(JDK提供的序列化方式效率稍微比JSON序列化低一些;并且JDK序列化很是严格,字段的增减,就极可能致使反序列失败,而JSON这方面兼容性较好)并发

假设从DB中查询须要2S,那么显然这段时间内过来的请求,在上述的代码下,会所有走DB查询,至关于缓存被直接穿透,这样的现象就称之为“缓存击穿”!ide

避免缓存击穿的思路分析

加synchronized?

对缓存击穿的一点思考3d

若是synchronized加在方法上,使得查询请求都得排队,原本咱们的本意是让并发查询走缓存。也就是如今synchronized的粒度太大了。blog

缩小synchronized的粒度?

对缓存击穿的一点思考接口

上面代码,在缓存有数据时,让查询缓存的请求没必要排队,减少了同步的粒度。可是,仍然没有解决缓存击穿的问题。内存

虽然,多个查询DB的请求进行排队,可是即使一个DB查询请求完成并设置到缓存中,其余查询DB的请求依然会继续查询DB!开发

synchronized+双重检查机制

对缓存击穿的一点思考同步

经过synchronized+双重检查机制:

在同步块中,继续判断检查,保证不存在,才去查DB。

代码抽象

发现没有,其实咱们处理缓存的代码,除了具体的查询DB逻辑外,其余都是模板化的。下面咱们就来抽象下!

一个查询DB的接口:

对缓存击穿的一点思考

既然查询具体的DB是由业务来决定的,那么暴露这个接口让业务去实现它。

一个模板:

对缓存击穿的一点思考

Spring不是有不少Template类么?咱们也能够经过这种思想对代码进行一个抽象,让外界来决定具体的业务实现,而把模板步骤写好。(有点相似AOP的概念)

改进后的代码:

对缓存击穿的一点思考

从这里能够看出,咱们并不关心缓存的数据从哪里加载,而是交给具体的使用方,并且使用方在使用时不再必关注缓存击穿的问题,由于咱们都给抽象了。

相关文章
相关标签/搜索