zoukankan      html  css  js  c++  java
  • 互联网缓存架构

    互联网公司在缓存架构上是区分很大的,往往是根据企业的业务量来进行选择的,可以看如下图

    在传统的小型互联网公司,采用网页静态化技术,freemarker来加快用户的体验速度,从来来提升响应,但是如果出现了缓存血崩,缓存击穿那么对数据库将会造成很大的压力,可能导致整个架构无法使用

    一 缓存击穿

        缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透,即使使用的es数据库,那么当大量数据进来之后还是对内容数据库压力造成很多问题

    解决方案:

    1.布隆过滤

      对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。还有最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

      补充:

          Bloom filter

      适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集

      基本原理及要点:对于原理来说很简单,位数组+k个独立hash函数。将hash函数对应的值的位数组置1,查找时如果发现所有hash函数对应位都是1说明存在,很明显这个过程并不保证查找的结果是100%正确的。同时也不支持删除一个已经插入的关键字,因为该关键字对应的位会牵动到其他的关键字。所以一个简单的改进就是counting Bloom filter,用一个counter数组代替位数组,就可以支持删除了。添加时增加计数器,删除时减少计数器。

         2. 缓存空对象. 将 null 变成一个值.

      也可以采用一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

     缓存空对象会有两个问题:

     第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。

     第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

    二  缓存血崩

      如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

      这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。
     rediscluster采用的是自研的hash slot算法,而不是采用传统的缓存hash算法

    ,hash算法 根据根据hash将数据分配到不同的redis上,那么当其中的一个挂掉之后,就是重新进行hash计算,导致分的服务缓存地址不对,会导致很多的缓存不可以使用,就会造成缓存问题,

    redis采用的hash slot是算法,算法将hash/16384槽,进行分配,当其中一个缓存服务挂掉之后,不会造成重新计算分配,只会存在一部分缓存失效

     1. 加锁排队. 限流-- 限流算法. 1.计数 2.滑动窗口 3.  令牌桶Token Bucket 4.漏桶 leaky bucket [1]

     在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

     业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。

    SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

         2.数据预热

      可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀

         3.做二级缓存,或者双缓存策略。

         A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。

    三  缓存类型:

      个人对缓存的理解就缓存其实是一种思想,缓存也是可以区分的,缓存可以分为cpu缓存,程序外缓存,程序内缓存

      1 cpu缓存,是处理器级缓存,如果缓存的数据被命中,那么他的响应速度是要超过程序外缓存和程序内缓存,

      CPU缓存的容量比内存小的多但是交换速度却比内存要快得多。缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。  [1] 
    缓存大小是CPU的重要指标之一,而且缓存的结构和大小对CPU速度的影响非常大,CPU内缓存的运行频率极高,一般是和处理器同频运作,工作效率远远大于系统内存和硬盘。实际工作时,CPU往往需要重复读取同样的数据块,而缓存容量的增大,可以大幅度提升CPU内部读取数据的命中率,而不用再到内存或者硬盘上寻找,以此提高系统性能。但是从CPU芯片面积和成本的因素来考虑,缓存都很小。
    按照数据读取顺序和与CPU结合的紧密程度,CPU缓存可以分为一级缓存,二级缓存,部分高端CPU还具有三级缓存,每一级缓存中所储存的全部数据都是下一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。当CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。一般来说,每级缓存的命中率大概都在80%左右,也就是说全部数据量的80%都可以在一级缓存中找到,只剩下20%的总数据量才需要从二级缓存、三级缓存或内存中读取,由此可见一级缓存是整个CPU缓存架构中最为重要的部分
      2 程序外缓存
      程序外缓存即指,需要单独启动的服务,例如redis,nginx mencacahe 这些都是需要开启单独的服务,是不存在程序服务中的
      3 程序内缓存:
      指的是依靠程序而存在的,不会存在其他问题,程序崩溃,缓存就没有用了,例如eacahe和堆,和常量池等,都是对数据进行一个缓存的,只要程序不蹦,那么这个缓存就是一直可用

    四  小型互联网架构的好处和坏处:

      小型互联网架构缓存,其实很多部分没有采用es,es开启对内存的占用还是很惊人的,而且在开发维护上对公司的人要求相对就要要求高了,,通过静态化技术可以减少页面加载的时间

    五  大型互联网架构的好处和坏处:

      大型互联网架构:采用nginx进行进行数据缓存,10分钟更新一次,对数据进行缓存,通过lua拉去redis缓存中的数据,,如果redis缓存挂掉了,那么就从ehcashe中获取数据,即使是redis缓存血崩了,还是可以从ehcahe中获取数据,因为ehcahe是基于程序而存在的,不需要单独开启服务,所以只要程序不挂.那么这个缓存就不会崩溃,只会存在缓存击穿问题,即使击穿之后就回去查询es内存数据,

  • 相关阅读:
    取最小未用的账号
    Oracle 同义词
    RMAN备份报 RMAN-06059 错误
    Oracle11g memory_target
    基础记录
    uboot启动流程
    android有关生命周期探讨
    can协议
    java虚拟机
    内存管理机制
  • 原文地址:https://www.cnblogs.com/xiufengchen/p/10642112.html
Copyright © 2011-2022 走看看