zoukankan      html  css  js  c++  java
  • Redis基础

    缓存穿透

    缓存穿透,是指查询一个数据库不存在的数据。对于系统A,假设一秒 5000 个请求,结果其中 4000 个请求是黑客发出的恶意攻击。黑客发出的那 4000 个攻击,缓存中查不到,每次你去数据库里查,也查不到。

    举个栗子。数据库 id 是从 1 开始的,结果黑客发过来的请求 id 全部都是负数。这样的话,缓存中不会有,请求每次都“视缓存于无物”,直接查询数据库。这种恶意攻击场景的缓存穿透就会直接把数据库给打死。

    image-20200308172751346

    处理方案

    1. 判断合法的请求:接口层增加校验,比如用户鉴权,参数做校验,不合法的校验直接 return,比如 id 做基础校验,id<=0 直接拦截。
    2. 当查询不存在时,也将结果保存在缓存中。但是这可能会存在一种问题:大量没有查询结果的请求保存在缓存中,这时我们就可以将这些请求的key设置得更短一些。
    3. 布隆过滤器(Bloom Filter):利用高效的数据结构和算法快速判断出你这个 Key 是否在数据库中存在。

    缓存击穿

    缓存击穿指的是:一个 Key 非常热点,在不停地扛着大量的请求,大并发集中对这一个点进行访问,当这个 Key 在失效的瞬间,持续的大并发直接落到了数据库上,就在这个 Key 的点上击穿了缓存。

    处理方案

    1. 多级缓存:结合redis缓存和本地缓存(ehcache、guava等)搭建多级缓存。将一些重要的热点数据存储到本地缓存中,有效缓解redis的压力。

    2. 用加锁或者队列的方式保证缓存的单线程(进程)写,在加锁方法内先从缓存中再获取一次,没有再查DB写入缓存。

      public static String getData(String key) throws InterruptedException {
              //从Redis查询数据
              String result = getDataByKV(key);
              //参数校验
              if (StringUtils.isBlank(result)) {
                  try {
                      //获得锁
                      if (reenLock.tryLock()) {
                          //去数据库查询
                          result = getDataByDB(key);
                          //校验
                          if (StringUtils.isNotBlank(result)) {
                              //插进缓存
                              setDataToKV(key, result);
                          }
                      } else {
                          //睡一会再拿
                          Thread.sleep(100L);
                          result = getData(key);
                      }
                  } finally {
                      //释放锁
                      reenLock.unlock();
                  }
              }
              return result;
          }
      

    缓存雪崩

    缓存雪崩是指:大量缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩,导致数据库CPU和内存负载过高,甚至宕机。

    缓存雪崩和缓存击穿情况比较相似,缓存击穿是一个高并发的热点key,在失效的瞬间,大量同个数据查询的请求直接落到数据库。而缓存雪崩是指大面积缓存在同一短时间内失效,导致大量各种数据请求落到数据库上。

    缓存击穿是点击破,缓存雪崩是面击破。

    举个栗子:如果首页所有 Key 的失效时间都是 12 小时,中午 12 点刷新的,我零点有个大促活动大量用户涌入,假设每秒 6000 个请求,本来缓存可以抗住每秒 5000 个请求,但是缓存中所有 Key 都失效了。此时 6000 个/秒的请求全部落在了数据库上,数据库必然扛不住,真实情况可能 DBA 都没反应过来直接挂了。

    image-20200308173225345

    处理方案

    1. 缓存高可用:搭建高可用redis集群,主从+哨兵,redis cluster,避免全盘崩溃。

      即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,例如 Redis Sentinel 和 Redis Cluster 都实现了高可用。

    2. 限流&降级: hystrix 限流&降级。

      当访问量剧增、服务出现问题仍然需要保证服务还是可用的。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级,这里会涉及到运维的配合。降级的最终目的是保证核心服务可用,即使是有损的。

    3. 多级缓存:结合redis缓存和本地缓存(ehcache、guava等)搭建多级缓存。将一些重要的热点数据存储到本地缓存中,有效缓解redis的压力。

    4. 缓存失效时间点均匀分布:尽量让失效时间点均匀分布,设置不同的过期时间。在设置Redis键的过期时间时,加上一个随机数,这样可以避免。

    5. Redis持久化和快速预热:redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

    总的来说缓存雪崩,可能是同一时间内大面积缓存时效,或者是缓存服务故障。大面积失效情况,可以在设置缓存有效期是增加一个随机值,使得缓存有效期分布均匀;或则设置多级缓存机制,多一层本地缓存机制,但是要考虑哪些数据适合放入本地缓存。缓存服务器故障情况,需要考虑缓存集群的高可用、缓存的持久化和快速预热。

    总结

    • 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。
    • 事中:本地 ehcache 缓存 + Hystrix 限流+降级,避免MySQL 被打死。
    • 事后:Redis 持久化 RDB+AOF,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

    参考资料

    https://www.cnblogs.com/yoishion/p/10791501.html

    面试前,我们要复习多少Redis知识点?

    https://juejin.im/post/5db66ed9e51d452a2f15d833

  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/zhaooo/p/13973890.html
Copyright © 2011-2022 走看看