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个用户的操作
    在这里插入图片描述

  • 相关阅读:
    单例模式的五种实现模式
    JAVA基础语法
    买卖股票的最佳时机 III
    leetcode 正则表达式 (动态规划)
    leetcode LRU缓存机制(list+unordered_map)详细解析
    leetcode 下一个排列(C++,STL源码解析)
    leetcode 编辑距离(动态规划)
    leetcode 字典序排数
    leetcode 字典序第K小数字
    leetcode 有效的括号(栈模拟)
  • 原文地址:https://www.cnblogs.com/guanhuohuo/p/12533562.html
Copyright © 2011-2022 走看看