zoukankan      html  css  js  c++  java
  • 【性能调优】高并发缓存穿透

    普通缓存使用

    当系统接收到一个获取数据的请求时,系统就会先从缓存中查找数据,而系统从缓存中查找数据时分两种情况:

    1. 如果缓存中有数据的话直接从缓存中读取数据,然后返回给请求方
    2. 如果缓存中没有那就从数据库中读取数据,然后在更新到缓存中,下次再获取这条数据时可以直接从缓存中读取
      在这里插入图片描述
      在并发较高时不建议使用缓存过期的策略,缓存一直存在,通过后台系统更新缓存系统中的数据,达到数据一致性的目的
      上面的方案在并发较高的情况下还会出现缓存穿透的情况

    缓存穿透

    缓存穿透指的是查询一个一定不存在的数据,由于缓存不命中时,需要从数据库中查询,而数据库也没有这条数据,这时候无法更新缓存,这将导致这个不存在的数据每次请求时都要到数据库中查询
    有人可以利用这个漏洞进行恶意攻击,将会对数据库造成非常大的压力,严重的话会导致数据库宕机

    解决方案
    方案一:
    在不存在的key预先设置一个值,比如设置为空字符串null,在返回这个空字符串null值的时候,我们应用就可以认为这是一个不存在的key,就可以决定是否需要等待还是继续访问,或者干脆放弃这次操作。如果继续等待访问,过一个时间轮询点后,再次请求这个key,如果取到的值不在是null,就可以认为这时候key是有值了。这就避免了穿透到数据库的情况

    方案二:
    布隆过滤器。用于检索一个元素是否在一个集合中,优点是空间效率和查询时间,缺失是有一定的误识别率并且删除困难

    缓存并发

    假设有多个获取同一条数据的请求,从缓存中没有查询到数据,这时所有的请求都会到数据库去查询,然后所有的请求再反复更新缓存数据,而且更新的是同一条数据,不仅增加查询数据库的压力,还会因为反复更新的问题,占用redis的请求资源,这就是缓存并发问题

    解决方案
    请求从客户端发起,请求先从缓存中读取数据,然后判断是否能从缓存中读取到数据,如果读取到数据就直接返回给客户端,流程结束。如果没有读取到,那么就在redis中使用setNX方法设置一个状态位,表示这是一种锁定状态,要是设置成功了,表示已经锁定成功,这时候请求从数据库中读取数据,然后更新缓存,最后再将数据返回给客户端,要是设置没成功的话,表示这个状态位已经被其他请求锁定,这个请求等待一段时间,会重新发起数据查询,这样就能保证在同一时间,只有一个请求来查询数据库更新缓存,其他请求只能等待重新发起查询,再次查询发现有缓存中有数据直接返回数据即可
    在这里插入图片描述

    缓存过期

    在请求过程中不断的往缓存中写入数据,这样缓存中的数据就会越来越多,但真正被经常访问的数据可能只是其中一小部分。所以在某些需求下,没有必要将所有数据放在缓存中,于是就设置缓存过期时间。这样不经常访问的数据就会自动过期

    如何设置缓存过期时间?
    一般情况下可能将缓存过期时间设置为固定的时间,比如1分钟、5分钟这些。
    并发很高的时候就会出现在某个时间点,用户同时设置了很多缓存,并且过期时间都一样。当缓存到期时,缓存同时失效,请求全部转发到数据库,这时数据库的压力就会瞬间增大,造成缓存雪崩的现象

    解决方案
    方案一:
    将缓存失效时间分散开。在原有失效时间基础上,增加一个随机值,这样每个缓存过期时间的重复率就会降低,很难引起缓存雪崩的现象
    方案二:
    缓存不过期。通过后台来更新缓存数据,避免缓存失效造成缓存雪崩

    缓存热点

    以一个用户中心为案例,每个用户都会首先获取自己的用户信息,然后再进行其他相关操作。
    有可能有这样的场景,大量相同的用户访问同一个项目,或者同一用户频繁访问同一模块,也就是说数据库存在的用户数据,可能某一用户的请求量非常大,有些用户的请求量比很小,因为用户量比较大,且受限于缓存空间的大小,不能把全部的用户数据都存放在缓存中,只能存放热点用户数据。

    如何判断热点数据
    通过判断数据最新访问时间来做排名,过滤掉不常访问的数据。
    先通过缓存系统做一个排序队列,比如存放1000个用户,系统会根据用户的访问时间,更新用户信息的时间,越是最近访问的用户排名越靠前,同时系统会定期过滤掉排名最后的200个用户,然后再从数据库中随机读取200个用户加入到队列,这样请求每次到达的时候会先从队列中获取用户信息,如果命中就根据用户userid再从另一个缓存结构中读取用户信息返回。在redis中,可以使用zadd方法和zrange方法来完成排序队列和取200个用户的操作
    在这里插入图片描述

  • 相关阅读:
    剑指Offer-30.连续子数组的最大和(C++/Java)
    剑指Offer-29.最小的K个数(C++/Java)
    UVA 1616 Caravan Robbers 商队抢劫者(二分)
    UVA 10570 Meeting with Aliens 外星人聚会
    UVA 11093 Just Finish it up 环形跑道 (贪心)
    UVA 12673 Erratic Expansion 奇怪的气球膨胀 (递推)
    UVA 10954 Add All 全部相加 (Huffman编码)
    UVA 714 Copying Books 抄书 (二分)
    UVALive 3523 Knights of the Round Table 圆桌骑士 (无向图点双连通分量)
    codeforecs Gym 100286B Blind Walk
  • 原文地址:https://www.cnblogs.com/guanhuohuo/p/12533562.html
Copyright © 2011-2022 走看看