转载自 https://www.cnblogs.com/sanday/p/7877693.html

缓存雪崩:由于原有的缓存过期失效,新的缓存还没有缓存进来,有一只请求缓存请求不到,导致所有请求都跑去了数据库,导致数据库IO、内存和CPU眼里过大,甚至导致宕机,使得整个系统崩溃。

解决思路:
1,采用加锁计数,或者使用合理的队列数量来避免缓存失效时对数据库造成太大的压力。这种办法虽然能缓解数据库的压力,但是同时又降低了系统的吞吐量。
2,分析用户行为,尽量让失效时间点均匀分布。避免缓存雪崩的出现。
3,如果是因为某台缓存服务器宕机,可以考虑做主备,比如:redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据,需要好好解决。

加锁:加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

public class CacheDemo

{

    public object GetCacheDataList()

        {

            const int cacheTime = 60;   

            const string lockKey = cacheKey;

            const string cacheKey = "datainfolist";      

            var cacheValue = CacheHelper.Get(cacheKey);

            if (cacheValue != null)

            {

                return cacheValue;

            }

            else

            {

                lock (lockKey)

                {

                    cacheValue = CacheHelper.Get(cacheKey);

                    if (cacheValue != null)

                    {

                        return cacheValue;

                    }

                    else

                    {

                        cacheValue = GetDataBaseInfo();              

                        CacheHelper.Add(cacheKey, cacheValue, cacheTime);

                    }                   

                }

                return cacheValue;

            }

        }

}

  标记失效缓存:

缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存。

  缓存数据:它的过期时间比缓存标记的时间延长1倍,例:标记缓存时间30分钟,数据缓存设置为60分钟。 这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存。

  这样做后,就可以一定程度上提高系统吞吐量。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

public object GetProductListNew()

        {

            const int cacheTime = 30;

            const string cacheKey = "product_list";

            //缓存标记。

            const string cacheSign = cacheKey + "_sign";

            

            var sign = CacheHelper.Get(cacheSign);

            //获取缓存值

            var cacheValue = CacheHelper.Get(cacheKey);

            if (sign != null)

            {

                return cacheValue; //未过期,直接返回。

            }

            else

            {

                CacheHelper.Add(cacheSign, "1", cacheTime);

                ThreadPool.QueueUserWorkItem((arg) =>

                {

                    cacheValue = GetProductListFromDB(); //这里一般是 sql查询数据。

                    CacheHelper.Add(cacheKey, cacheValue, cacheTime*2); //日期设缓存时间的2倍,用于脏读。               

                });

                

                return cacheValue;

            }

        }

  缓存穿透:

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。

  解决的办法就是:如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库中查询。

解决思路:

1,如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。

2,根据缓存数据Key的规则。例如我们公司是做机顶盒的,缓存数据以Mac为Key,Mac是有规则,如果不符合规则就过滤掉,这样可以过滤一部分查询。在做缓存规划的时候,Key有一定规则的话,可以采取这种办法。这种办法只能缓解一部分的压力,过滤和系统无关的查询,但是无法根治。

3,采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的BitSet中,不存在的数据将会被拦截掉,从而避免了对底层存储系统的查询压力。关于布隆过滤器,详情查看:基于BitSet的布隆过滤器(Bloom Filter)

大并发的缓存穿透会导致缓存雪崩。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public object GetProductListNew()

        {

            const int cacheTime = 30;

            const string cacheKey = "product_list";

            var cacheValue = CacheHelper.Get(cacheKey);

            if (cacheValue != null)

                return cacheValue;

                

            cacheValue = CacheHelper.Get(cacheKey);

            if (cacheValue != null)

            {

                return cacheValue;

            }

            else

            {

                cacheValue = GetProductListFromDB(); //数据库查询不到,为空。

                

                if (cacheValue == null)

                {

                    cacheValue = string.Empty; //如果发现为空,设置个默认值,也缓存起来。               

                }

                CacheHelper.Add(cacheKey, cacheValue, cacheTime);

                

                return cacheValue;

            }

        }

  把空结果,也给缓存起来,这样下次同样的请求就可以直接返回空了,即可以避免当查询的值为空时引起的缓存穿透。同时也可以单独设置个缓存区域存储空值,对要查询的key进行预先校验,然后再放行给后面的正常缓存处理逻辑。

缓存预热

  缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样避免,用户请求的时候,再去加载相关的数据。

  解决思路:

    1,直接写个缓存刷新页面,上线时手工操作下。

    2,数据量不大,可以在WEB系统启动的时候加载。

    3,定时刷新缓存,

缓存更新

  缓存淘汰的策略有两种:

    (1) 定时去清理过期的缓存。

    (2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。

  两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂,具体用哪种方案,大家可以根据自己的应用场景来权衡。1. 预估失效时间 2. 版本号(必须单调递增,时间戳是最好的选择)3. 提供手动清理缓存的接口。

redis缓存雪崩和缓存穿透相关推荐

  1. Redis总结(五)缓存雪崩和缓存穿透等问题

    前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhong/category/771056.html .今 ...

  2. Redis专题-缓存穿透、缓存雪崩、缓存击穿

    一.缓存穿透 缓存穿透概念 缓存穿透是指查询一个一定不存在的数据,在数据库没有,自然在缓存中也不会有.导致用户查询的时候,在缓存中找不到对应key的value,每次都要去数据库再查询一遍,如果从存储层 ...

  3. Redis 的缓存异常处理 —— 缓存雪崩、缓存击穿、缓存穿透

    Redis 的缓存异常处理 -- 缓存雪崩.缓存击穿.缓存穿透 在实际应用 Redis 过程中,如果将 Redis 作为数据库的缓存,经常会遇到这几个问题:缓存雪崩.缓存击穿.缓存穿透等. 缓存雪崩 ...

  4. Redis缓存雪崩、缓存穿透、热点Key解决方案和分析

    转载自  https://blog.csdn.net/wang0112233/article/details/79558612 https://www.sohu.com/a/230787856_231 ...

  5. redis缓存穿透、缓存雪崩、缓存击穿、并发竞争

    关注微信公众号"虾米聊吧",每天更新一篇技术文章,文章内容涵盖架构师成长必经之路应掌握的技术,一起学习,一起交流. 缓存穿透.缓存雪崩.缓存击穿.并发竞争是缓存最常见的几个问题,接 ...

  6. Redis缓存雪崩、缓存穿透、热点Key

    我们通常使用 缓存 + 过期时间的策略来帮助我们加速接口的访问速度,减少了后端负载,同时保证功能的更新. 1.缓存穿透 缓存系统,按照KEY去查询VALUE,当KEY对应的VALUE一定不存在的时候并 ...

  7. Redis系列教程(三):如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题

    Java相关的面试都会问到缓存的问题:史上最全Redis面试49题(含答案):哨兵+复制+事务+集群+持久化等,除此之外还会问到缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级等不常见的问题,但却是非 ...

  8. 【重难点】【Redis 03】缓存雪崩、缓存穿透、缓存击穿、Redis 的内存过期策略、并发读写和双写

    [重难点][Redis 03]缓存雪崩.缓存穿透.缓存击穿.Redis 的内存过期策略.并发读写和双写 文章目录 [重难点][Redis 03]缓存雪崩.缓存穿透.缓存击穿.Redis 的内存过期策略 ...

  9. 实例解读什么是Redis缓存穿透、缓存雪崩和缓存击穿

    from:https://baijiahao.baidu.com/s?id=1619572269435584821&wfr=spider&for=pc Redis缓存的使用,极大的提升 ...

  10. 一张图搞懂 Redis 缓存雪崩、缓存穿透、缓存击穿

    作者 |  雷架 文章来源 | 爱笑的架构师 (id :DancingOnYourCode) 缓存异常场景分类 在实际生产环境中有时会遇到缓存穿透.缓存击穿.缓存雪崩等异常场景,为了避免异常带来巨大损 ...

最新文章

  1. linux gcc 静态编译 减小体积
  2. 40.公约数和公倍数
  3. [云炬创业基础笔记]第七章创业资源测试5
  4. 修改Visual Stdio 2010界面,以及添加一些其它VS2010的插件
  5. CVPR!你凭什么收录我3篇论文!? 1
  6. 求最长回文串-从动态规划到马拉车之路(下)
  7. Vue-在data中引入静态图片路径
  8. js基础练习:实现资料查找
  9. CreatorPrimer|优化编辑器
  10. scala ip转换器
  11. 解决insmod: error inserting 'hello.ko': -1 Invalid module format
  12. MongoDB介绍与部署使用
  13. rpm -ivh *rpm 是什么意思
  14. 学大数据专业未来应该怎么就业?有什么岗位?
  15. 检查网络端口是否正常
  16. C++ 计算球体体积
  17. 一款轻、快、无广告的杀毒安全软件(火绒5.0)
  18. Java(SpringMVC03)(SSM整合1)
  19. C语言中除以怎么使用
  20. 个人PC搭建自己的虚拟服务器

热门文章

  1. 视频码率,帧率和分辨率的区别
  2. C++中Struct和Class的区别
  3. c++继承:共有、私有、保护继承
  4. 1.6 网络编程之 UDP通信
  5. c++ template笔记(3)非类型模板参数nontype template parameters
  6. WebRTC 的音频处理流水线
  7. 如何正确、高效地阅读源代码?
  8. 小短文 | 高并发系统,如何计算并发量和峰值数据?
  9. H.264专利费不受FRAND限制 Android设备商受影响
  10. 浅谈缓存最终一致性的解决方案