论缓存

被动式缓存

大型网站架构的三要素缓存异步并行计算,其中缓存是最简单也是最常见的。

简单的缓存实现

所有人都会看到过,代码中无处不在都充斥着这类的实现,其实就是一种最简易的缓存实现。

    if(data == null){
      data = getData();
    }
    return data;

而这种实现在多线程并发下,就会出现数据重复获取的问题,设置会出现数据不一致的问题。

多线程下的缓存实现

为了解决数据重复获取的问题,我们只需要简单的使用锁即可解决。

    if(data == null){
      lock(data){
        if(data == null){ // double checked
          data = getData();
        }
      }
    }
    return data;

基本来说,一个小型网站到这一步基本就足够了。但是一个大型网站,这个实现仍然是有问题的。

一个大型网站,基本都会有很多服务器,使用分布式部署。解决了多线程并发问题,但是加锁也无法解决多服务器并发问题。

因为缓存是散列在各个服务器之中,独立存在。所以很容易出现用户看到的数据不一致的问题。

数据一致性的问题

为了解决数据一致性问题,我们一般的做法是使用独立的缓存服务器这种方案。

大概讲解一下缓存的分类:

我一般缓存把分为两大类本地远程
同时又分别细分内核内存硬盘缓存三种。

本地 -- | -- 内核
       | -- 内存
       | -- 硬盘

远程 -- | -- 内核
       | -- 内存
       | -- 硬盘

性能优劣排行,从上到下,从本地内核最优到远程硬盘最次。

独立的缓存服务器一般使用的技术是Memcache或者Redis之类的。都是属于远程内存的方案。

以使用Redis为例,可以轻松的达到20w的QPS。基本可以满足了绝大多数的网站性能要求。

但是对于一个大型网站,只使用远程型的缓存,20w的QPS显然是不够的。

多级缓存

多级缓存其实我们并不陌生,几乎所有科班出身的都会学过计算机原理,CPU就是一个典型的多级缓存使用案例。

使用多级缓存的时候,无非就是在远程缓存服务器存一份,本地也同时存一份。

    data = getLocalData();
    if(data == null){
        data = getRemoteData();
        if(data == null){
          data = getData();
          setLocalData(data);
          setRemoteData(data);
        }
      }
    }
    return data;

但是也因此引入了两个问题:

双倍过期时间问题

假设缓存过期时间设置是10s。

A服务器获取数据,分别在缓存服务器缓存10s,本地缓存10s。

9秒900ms后,B服务器去缓存服务器上获取数据,成功获取,并且缓存10s。

  A 服务器       |----10s----|
  远程服务器      |----10s----|
  B 服务器                  |----10s----|
  实际的缓存时间   |------ 19s900ms -----|

为了解决这个问题,只需要在缓存的数据内添加缓存的到期时间即可。

    class doubleCacheModel<T>{
      Datetime expireDatetime;
      T data;
    }

B服务器从缓存服务器取到的数据后,同时取到当前缓存的过期时间,B服务器缓存到指定的时间即可实现缓存过期时间一致的效果。

数据不一致的问题

沿用上面的假设,C服务器在5s的时候修改了数据,更新了本地缓存数据,同时更新了缓存服务器的数据。

但是A服务器上的数据仍然是旧的。而用户的访问随机分布在A和C之间。那么就会出现,每一次刷新,拿到的数据都不一样的灵异事件了。

为了解决数据一致性问题,我们只需开启一个监听线程即可,当缓存数据发生修改时,发起通知,收到通知的服务器进行相关的数据更新即可。

结束

小小的一个缓存,在做之前根本想不到会这么多问题。可惜即便做了这么多,性能还是没有达标。不知不觉已经这么晚了,留下一个思考,如果我还记得的话再来更新。

思考:访问性能波峰问题

假设,缓存时间是10s,读取数据的时间是100ms,那么访问的效果大概如下图:

|-----10s----|--|----10s-----|--|-----10s----|--|----10s-----|

每10s就会有一波访问阻塞的问题。

长缓存时间,可以缓解这个问题,但是就会加剧数据延迟问题。

短缓存时间,可以缓解数据延迟,但是阻塞等待却越发明显。

posted on 2016-07-10 00:05  艾晨爸  阅读(161)  评论(0编辑  收藏  举报

导航