美文网首页阿里云程序员
并发下的缓存设计

并发下的缓存设计

作者: 8033b4d1f3ec | 来源:发表于2018-06-22 20:08 被阅读13次

之前线上发生过缓存设计导致系统宕机的事故,让我很奇怪的是,已经缓存了数据,还是导致数据库cpu过高,让我很是奇怪,代码是这样的:

public List<Msg> getMsgList() {
    String json = redis.get("cachekey");
    if (!StringUtils.isEmpty(json)) {
        return new Gson().fromJson(json, new TypeToken<List<Msg>>(){}.getType());
    } else {
        List<Msg> list=db.getMsgList();
         if (!CollectionUtils.isEmpty(list)) {
            redis.set(key,new Gson.toJson(list));
            redis.expire(key,60);
         }
         return list;
    }
}

上面这段代码是大多数缓存应用场景的设计,优先读取缓存,如果缓存过期,那么从db加载到cache,然后设置过期时间。那么有什么问题呢?上面这个方法的应用场景说下,从数据库中读取最后300条留言数据做列表展示,因为做了一个活动,导致人数过多,每秒大概2w请求,这样导致的问题是,在缓存失效的那一瞬间,大量的请求直接到了db,会直接导致数据库大量的计算,导致cpu负荷过高。在请求并发上来的时候,直接导致数据库挂了。

所以在大量并发请求的情况下和初始化非常占据资源的情况下是不适合用类似的方式做缓存设计的。我之前读过memcache的mutex设计,所以我第一时间想到的是mutex的设计思想,这个思想的思路是这样的,如果缓存中的数据已过期,那么设置一个额外的key来做过度,在这个过度时间,去做db到缓存的初始化。redis的实现代码大致是这样:

public String getMsgList(){
    String json=redis.get("cachekey");
    if (json==null) {
       if(redis.setnx("mutexKey","1")==1){
          redis.expire("mutexKey",30);
          String value=db.get();
          redis.set(key,value);
          redis.expire("cachekey",60*1000);
          redis.del(mutexKey);
          return value;
       } else {
          Thread.sleep(50);
          return redis.get("cachekey");
       }
    } else {
       return json;
    }
}

这个思路来自于:tim老师的mutextKey设计 ,因为redis本身是单线程的,所以setnx命令能够保证只有一个线程进入.

第二个思路是在新增数据的入口处,维护一个队列,因为业务中是获取最新的留言信息,所以非常适合用队列来做,每次新增数据,往队列新增数据,如果超出长度,对队列进行修剪:

public void pushList(String msg){
    int maxCount=10;
    int length=redis.llen("cachekey");
    if(length>=maxCount){
       redis.ltrim(0,maxCount-1);
    }
    redis.lpush("cachekey",msg);
}

这样读取的时候,只需要使用lrange(0,-1)命令就可以读取到最新的信息了,这种方法也避免掉了,大量并发的时候,大量请求打到db上。实际应用中,我使用了第二种思路,用队列处理。这两种思路都是可以的,当我第一次在tim老师的博客中看到第一种思路的时候,简直惊叹这种设计,原来有这么优秀的设计,可以避免db初始化耗资源的问题。

tim老师还有很多优秀的文章都值得阅读,众所周知新浪微博的用户数量非常的大,很多问题其实我们自己平时可以去考虑这其中的实现,比如关注列表,粉丝列表怎么实现,有些大v有几千万的粉丝,这种设计如何去做才能最优,消息的推送如何去做,千万级的粉丝的推送问题如何优化,是主动推还是拉取。

微博个人主页关注列表的动态如何设计优化,还有每条动态的评论,内容。社会上热门事件可能导致大量的围观。标签下的内容匹配设计等等,都是非常有挑战的设计。

参考资料:https://timyang.net/tag/mutex/

相关文章

  • 并发下的缓存设计

    之前线上发生过缓存设计导致系统宕机的事故,让我很奇怪的是,已经缓存了数据,还是导致数据库cpu过高,让我很是奇怪,...

  • 高并发与缓存

    本文主要讲述高并发下缓存会出现的问题。 在高并发下,缓存会出现的问题有:缓存一致性、并发问题、穿透问题、缓存的雪崩...

  • 缓存设计

    目录 缓存设计需要考虑的地方 项目代码编写 mybaits缓存设计原理 guava缓存设计原理 本地缓存设计需要考...

  • page cache页面缓存

    为什么设计缓存? 如何设计缓存? 页面缓存都缓存什么?

  • 浏览器缓存和压缩优化技术

    一、HTTP缓存机制 高并发下只能通过提升服务器负载解决?缓存只能做数据库缓存?启用浏览器缓存 缓存分类:HTTP...

  • 高并发下的各种缓存

    前言 Cache在大家最开始接触开发的时候应该就听过许多了,比如浏览器缓存、OS中的缓存、什么缓存一致性等等,各式...

  • 如何正确的使用缓存,什么是缓存穿透

    什么是缓存穿透 看如下这个代码案例: 上述案例中没有缓存穿透解决方案,在高并发下,如果缓存过期,会有多个请求到数据...

  • LFU

    参考 LeetCode算法题解:LFU CacheLFU Cache 最近最不常用页面置换缓存器 题目要求 设计并...

  • 图片缓存

    方案一:无沙盒从缓存取图,并显示如缓存无图,则下载下载完后,存入缓存,并显示方案二:有沙盒从缓存取图,并显示如缓存...

  • iOS架构设计-URL缓存(上)

    iOS架构设计-URL缓存(上) iOS架构设计-URL缓存(上)

网友评论

    本文标题:并发下的缓存设计

    本文链接:https://www.haomeiwen.com/subject/vcdlyftx.html