遇到的一个缓存穿透故障

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linsongbin1/article/details/85276330

概述


在昨天下午,在做业务系统每日巡检的时候,发现营销系统的日志里,出现了209次ERROR,内容如下:

获取商品详情优惠券出错,request:{“productId”:123456,“shopId”:123456,“userId”:123456}
获取商品详情优惠券出错,request:{“productId”:123456,“shopId”:123456,“userId”:123456}
获取商品详情优惠券出错,request:{“productId”:123456,“shopId”:123456,“userId”:123456}

由于是用grep命令找出来,具体是什么报错原因,不清楚,因此用了之前文章shell查找文件显示行号和对应区间的内容里提到的技巧,找出报错的详细内容。

Cause: org.springframework.jdbc.CannotGetJdbcConnectionException,Connection is not available

从日志上看,是获取不到数据库连接了,但是比较奇怪,获取商品详情优惠券这个接口我是加了缓存的,详情请看缓存时间小技巧-随机打散,理论上不太可能有很多的请求穿透到数据库才对呀。因此仔细分析了发生报错的时间和报错的请求入参,发现报错时间集中在中午12点01分这一分钟里,且大部分入参都是同一个shopId的。至于如何用awk统计shopId,请参考awk神器呀

由于店铺的商品详情是按照店铺id作为key来缓存的,一旦某个时间段,店铺的并发请求量一大,而刚好缓存又失效了,如果没有做热key防护,瞬间就有很多请求打到数据库了,造成数据库连接不够用。


解决方案


由于是以店铺id作为key的,只要这个店铺的用户进入到商详,就会调用获取商详优惠券的接口。这种key属于大key,如果我们缓存的key加上userId的话,那就没问题,因为按照userId打散了。不过这样做有个问题,就是缓存的key非常非常多,不建议这么干。

我这边是这么做的:
第一:增加营销系统的数据库连接数,之前才配置了几十个,对于这种C端应用,确实配置少了。
第二:加一个本地缓存,并针对本地缓存,做一个进程级别的本地锁,同一个key并发过来查询,如果从缓存获取不到数据,则放一个请求过去,其他请求继续等待。

猜你喜欢

转载自blog.csdn.net/linsongbin1/article/details/85276330