记一次缓存穿透问题

2 篇文章 0 订阅

1. 场景描述

公司产品的一次抽奖活动,在压测过程中把数开始了一俩轮没有问题,就在测第三轮的时候响应速度异常的慢数据库的链接也满了(当时是单机测试),当时感觉很奇怪明明加了缓存(用的是memcached)为什么会干到数据库中了当时首先想到的是memcached挂了经过排查不是,难道时缓存穿透了?有事一顿测试排查,果然,有个key的时间恰好在并发进来的时候过期了导致大量的请求干到了数据里。既然找到问题了那么接下来就是写码的时候了。

2.代码

缓存穿透前的代码

1.  public boolean drawReward(String goodsId) {
2.      CacheClient client = CacheFactory.getInstance();
3.      String key = String.format(CacheConstants.KEY_GOODS_ENTITY,goodsId);
4.      String Cache = client.get(key);
5.      List<Goods> goodsList = null;
6.      if (Cache == null || Cache.trim().equals("")) {
7.          goodsList = baseMapper.getGoodsList(goodsId);
10          client.set(key, goodsList,CacheConstants.GOODS_TLL);
13.     } else {
14.         goodsList = (List<Goods>) DataHelper.readList(Cache, Goods.class);
15.     }
16.     return goodsList;
17. }

诈一下看这段缓存使用的并没有什么问题,但是在高并发下这段缓存存在着致命的危机,致命位置在于代码第7行dao层的数据读取当并发进来的时候GOODS_TLL有效期刚刚截止,或者后台更新了物品数据(无良产品欺诈用户不可取)那么第6行代码不是线程安全的无法并发处理那么需要怎么加锁呢?

改进

1.  public boolean drawReward(String goodsId) {
2.      CacheClient client = CacheFactory.getInstance();
3.      String key = String.format(CacheConstants.KEY_GOODS_ENTITY,goodsId);
4.      String Cache = client.get(key);
5.      List<Goods> goodsList = null;
6.      if (Cache == null || Cache.trim().equals("")) {
7.          //保险机制
8.          synchronized (this) {
9.              Cache = client.get(key);
10.             if (!StringUtils.isEmpty(Cache)) {
11.                 goodsList = (List<Goods>) DataHelper.readList(Cache, Goods.class);
12                  return goodsList;
13              }
14.             goodsList=baseMapper.getGoodsList(goodsId);
15.             client.set(key, DataHelper.writeList(goodsList),CacheConstants.GOODS_TLL);
16          }
17.     } else {
18.         goodsList = (List<Goods>) DataHelper.readList(Cache, Goods.class);
19.     }
20.     return goodsList;
21. }

改进后的数据读取加上了同步锁保证了每次数据都能击中缓存,经过测试TPS达到8000程序稳稳的运行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值