• 论缓存


    被动式缓存

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

    简单的缓存实现

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

        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就会有一波访问阻塞的问题。

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

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

  • 相关阅读:
    xPath用法
    http post 接口
    关于WSSE验证-- 一种验证用户的方法
    java资源文件解读
    dom4j读取xml
    docker安装mysql
    php.ini配置max_execution_time和FPM配置request_terminate_timeout
    《高德拉特约束理论》
    Python爬虫-播报天气信息(生成exe文件)待续
    pyhon-爬虫实战抓取豆瓣top250到mysql
  • 原文地址:https://www.cnblogs.com/quan2005/p/5656903.html
Copyright © 2020-2023  润新知