阿里一面 缓存穿透、缓存击穿、缓存雪崩和热点数据失效问题的解决方案

作者:乔二爷,来自:乔二爷(ID:hellozhouq)

1 前言

昨天晚上接到阿里的电面电话,过程中就问到了关于缓存相关的问题。虽然以前接触过,多多少少了解了一些。但是之前自己并没有好好记录这些内容,在真正面试的时候,并没有回答得出来。今天记录一下,长长记性。

在我们的平常的项目中多多少少都会使用到缓存,因为一些数据我们没有必要每次查询的时候都去查询到数据库。特别是高 QPS 的系统,每次都去查询数据库,对于你的数据库来说将是灾难。

今天我们不牵涉多级缓存的知识,就把系统使用到的缓存方案,不管是一级还是多级的都统称为缓存,主要是为了讲述使用缓存的时候可能会遇到的一些问题以及一些解决办法。

我们使用缓存时,我们的业务系统大概的调用流程如下图:

当我们查询一条数据时,先去查询缓存,如果缓存有就直接返回,如果没有就去查询数据库,然后返回。这种情况下就可能会出现一些现象。

2 缓存穿透

2.1 什么是缓存穿透

正常情况下,我们去查询数据都是存在。那么请求去查询一条压根数据库中根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。

这种查询不存在数据的现象我们称为缓存穿透。

2.2 穿透带来的问题

试想一下,如果有黑客会对你的系统进行攻击,拿一个不存在的id 去查询数据,会产生大量的请求到数据库去查询。可能会导致你的数据库由于压力过大而宕掉。

2.3 解决办法

2.3.1 缓存空值

之所以会发生穿透,就是因为缓存中没有存储这些空数据的key。从而导致每次查询都到数据库去了。

那么我们就可以为这些key 设置的值设置为null 丢到缓存里面去。后面再出现查询这个key 的请求的时候,直接返回null ,就不用在到 数据库中去走一圈了。但是别忘了设置过期时间。

2.3.2 BloomFilter

BloomFilter 类似于一个hase set 用来判断某个元素(key)是否存在于某个集合中。具体概念

这种方式在大数据场景应用比较多,比如 Hbase 中使用它去判断数据是否在磁盘上。还有在爬虫场景判断url 是否已经被爬取过。

这种方案可以加在第一种方案中,在缓存之前在加一层 BloomFilter ,在查询的时候先去 BloomFilter 去查询 key 是否存在,如果不存在就直接返回,存在再走查 缓存 -> 查 DB。

流程图如下:

2.4 如何选择

针对于一些恶意攻击,攻击带过来的大量key 是不存在的,那么我们采用第一种方案就会缓存大量不存在 key 的数据。此时我们采用第一种方案就不合适了,我们完全可以先对使用第二种方案进行过滤掉这些key。

针对这种key 异常多,请求重复率比较低的数据,我们就没有必要进行缓存,使用第二种方案直接过滤掉。

对于空数据的key 有限的,重复率比较高的,我们则可以采用第一种方式进行缓存。

3 缓存击穿

3.1 什么是击穿

缓存击穿是我们可能遇到的第二个使用缓存方案可能遇到的问题。

在平常高并发的系统中,大量的请求同时查询一个 key 时,此时 这个key 正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们成为击穿。

3.2 会带来什么问题

会造成某一时刻数据库请求量过大,压力剧增。

3.3 如何解决

上面的现象是多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。

4、缓存雪崩

4.1 什么是缓存雪崩

缓存的情况是说,当某一时刻发生大规模的缓存失效的情况。比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上面。结果就是DB 称不住,挂掉。

4.2 解决办法

4.2.1 事前:使用集群缓存,保证缓存服务的高可用

这种方案就是在发生雪崩前对缓存集群实现高可用,如果是使用 Redis,可以使用 主从+哨兵 ,Redis Cluster 来避免 Redis 全盘崩溃的情况。

4.2.2 事中:使用 ehcache 本地缓存 + Hystrix 限流&降级 ,避免 MySQL 被打死的情况发生。

使用 ehcache 本地缓存的目的也是考虑在 Redis Cluster 完全不可用的时候,ehcache 本地缓存还能够支撑一阵。

使用 Hystrix 进行 限流 & 降级 ,比如一秒来了5000个请求,我们可以设置假设只能有一秒 2000 个请求能通过这个组件,那么其他剩余的 3000 请求就会走限流逻辑,然后去调用我们自己开发的降级组件(降级)。比如设置的一些默认值呀之类的。以此来保护最后的 MySQL 不会被大量的请求给打死。

4.2.3 事后:开启 Redis 持久化机制,尽快恢复缓存集群

一旦重启,就能从磁盘上自动加载数据恢复内存中的数据。

防止雪崩方案如下图所示:

5 热点数据集中失效问题怎么解决

我们在设置缓存的时候,一般会给缓存设置一个失效时间,过了这个时间,缓存就失效了。对于一些热点的数据来说,当缓存失效以后会存在大量的请求过来,然后打到数据库去,从而可能导致数据库崩溃的情况。

5.1 解决办法

5.1.1 设置不同的失效时间

为了避免这些热点的数据集中失效,那么我们在设置缓存过期时间的时候,我们让他们失效的时间错开。比如在一个基础的时间上加上或者减去一个范围内的随机值。

5.1.2 互斥锁

结合上面的击穿的情况,在第一个请求去查询数据库的时候对他加一个互斥锁,其余的查询请求都会被阻塞住,直到锁被释放,从而保护数据库。但是也是由于它会阻塞其他的线程,此时系统吞吐量会下降。需要结合实际的业务去考虑是否要这么做。

【End】

老王给大家准备一份「Java最常见200+面试题全解析」,助力大家找到更好的工作,这份面试题包含的模块:

  • Java、JVM 最常见面试题解析

  • Spring、Spring MVC、MyBatis、Hibernate 面试题解析

  • MySQL、Redis 面试题解析

  • RabbitMQ、Kafka、Zookeeper 面试解析

  • 微服务 Spring Boot、Spring Cloud 面试解析

扫描下面二维码付费阅读

关注下方二维码,订阅更多精彩内容。

转发朋友圈,是对我最大的支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/546664.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fix chrome 下flash crash的问题

2019独角兽企业重金招聘Python工程师标准>>> 本来好好的,结果不知道为什么,在MAC下使用chrome不断出现flash插件的错误,网上搜了一下,看这里,要把chrome自带的flash插件注释掉。重启chrome好象是没什么问题…

为什么阿里巴巴建议集合初始化时,指定集合容量大小?

集合是Java开发日常开发中经常会使用到的。在之前的一些文章中,我们介绍过一些关于使用集合类应该注意的事项,如《为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作》。关于集合类,《阿里巴巴Java开发手册》中其实还有另外一个…

十五、Python操作mysql数据库

利用Navicat Premium 15软件连接mysql数据库,新建testdb数据库,并添加2个表usertest和userinfo。 main.py #!/usr/bin/python3 # -*- coding: utf-8 -*- import reimport pymysql # 导入模块myConn pymysql.connect(host127.0.0.1, # 主机模块port33…

面试必备的分布式事物方案

四月初,去面试了本市的一家之前在做办公室无人货架的公司,虽然他们现在在面临着转型,但是对于我这种想从传统企业往互联网行业走的孩子来说,还是比较有吸引力的。在面试过程中就提到了分布式事物问题。我又一次在没有好好整理的问…

记住:永远不要在MySQL中使用UTF-8

原文地址:https://dwz.cn/QS4wLyjh最近我遇到了一个bug&#xff0c;我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串&#xff0c;然后出现了一个离奇的错误&#xff1a;Incorrect string value: ‘\xF0\x9F\x98\x83 <…’ for column ‘summary’ at row 1我…

面试官:不使用synchronized和lock,如何实现一个线程安全的单例?

单例&#xff0c;大家肯定都不陌生&#xff0c;这是Java中很重要的一个设计模式。稍微了解一点单例的朋友也都知道实现单例是要考虑并发问题的&#xff0c;一般情况下&#xff0c;我们都会使用synchronized来保证线程安全。那么&#xff0c;如果有这样一道面试题&#xff1a;不…

Mac OS X中配置Apache

我使用的Mac OS X版本是10.8.2&#xff0c;Mac自带了Apache环境。 启动Apache设置虚拟主机启动Apache 打开“终端(terminal)”&#xff0c;输入 sudo apachectl -v&#xff0c;&#xff08;可能需要输入机器秘密&#xff09;。如下显示Apache的版本 接着输入 sudo apachectl st…

你真的理解零拷贝了吗?

作者&#xff1a;ksfzhaohui 来源&#xff1a;http://t.cn/ESALgwV前言从字面意思理解就是数据不需要来回的拷贝&#xff0c;大大提升了系统的性能&#xff1b;这个词我们也经常在java nio&#xff0c;netty&#xff0c;kafka&#xff0c;RocketMQ等框架中听到&#xff0c;经常…

一、华为鸿蒙开发HUAWEI DevEco Studio下载、安装与配置

一、HUAWEI DevEco Studio下载 https://developer.harmonyos.com/cn/develop 二、HUAWEI DevEco Studio安装 解压后&#xff0c;双击安装包。 打开启动 DevEco Studio 三、DevEco Studio配置 DevEco Studio开发环境需要依赖于网络环境&#xff0c;需要连接上…

从JDK中,我们能学到哪些设计模式?

作者&#xff1a;肥朝 来自&#xff1a;肥朝&#xff08;ID&#xff1a;feichao_java&#xff09;结构性模式&#xff1a;适配器模式&#xff1a;常用于将一个新接口适配旧接口肥朝小声逼逼&#xff1a;在我们业务代码中经常有新旧接口适配需求&#xff0c;可以采用该模式。桥…

二、华为鸿蒙开发DevEco Studio运行第一个Hello World工程

1.打开DevEco Studio,创建一个Empty Ability(Java)工程,工程类型:Application 2.按照下图,Tools->Device Manager打开设备管理

解析url

2019独角兽企业重金招聘Python工程师标准>>> #include <stdio.h> #include <string.h> #include <stdlib.h>// 解析url&#xff0c;作为示例&#xff0c;很多情况没考虑&#xff0c;比如说user,pass之类的 int parse_url(char *url, char **serve…

面试官:讲一下Jvm中如何判断对象的生死?

但凡问到 JVM&#xff08;Java 虚拟机&#xff09;通常有 99% 的概率一定会问&#xff0c;在 JVM 中如何判断一个对象的生死状态&#xff1f;判断对象的生死状态的算法有以下几个&#xff1a;1、引用计数器算法引用计算器判断对象是否存活的算法是这样的&#xff1a;给每一个对…

三、华为鸿蒙HarmonyOS应用开发HUAWEI DevEco Studio实现页面跳转

在上一节二、华为鸿蒙开发DevEco Studio运行第一个Hello Word工程 基础上进行下面步骤。 在Java UI框架中,提供了两种编写布局的方式:在XML中声明UI布局和在代码中创建布局。这两种方式创建出的布局没有本质差别,为了熟悉两种方式,我们将通过XML的方式编写第一个页面,通过…

MVVM架构~前台后台分离的思想与实践

返回目录 MVVM是一种架构思想&#xff0c;是一种解决问题的方式&#xff0c;对于一个项目&#xff0c;一个功能模块&#xff0c;你可以选择使用&#xff2d;&#xff36;&#xff36;&#xff2d;的架构来实现&#xff0c;而knockoutjs只是实现MVVM的一种工具&#xff0c;它是在…

Java中所有锁介绍

在读很多并发文章中&#xff0c;会提及各种各样锁如公平锁&#xff0c;乐观锁等等&#xff0c;这篇文章介绍各种锁的分类。介绍的内容如下&#xff1a;1.公平锁 / 非公平锁2.可重入锁 / 不可重入锁3.独享锁 / 共享锁4.互斥锁 / 读写锁5.乐观锁 / 悲观锁6.分段锁7.偏向锁 / 轻量…

python深拷贝,浅拷贝,赋值引用

1.在python中&#xff0c;对象赋值实际上是对象的引用。当创建一个对象&#xff0c;然后把它赋给另一个变量的时候&#xff0c;python并没有拷贝这个对象&#xff0c;而只是拷贝了这个对象的引用 &#xff08;1&#xff09;直接赋值,默认浅拷贝传递对象的引用而已,原始列表改变…

pjtool用到的数据库----oracle范畴

PL/SQL Developer 专门面向Oracle数据库存储程序单元的开发 PL/SQL&#xff1a;过程化SQL语言转载于:https://www.cnblogs.com/ejllen/p/3684890.html

如何让mysql索引更快一点

后端开发&#xff0c;公众号内容包括但不限于 python、mysql、数据结构和算法、网络协议、Linux。技术人怎能只有技术和代码&#xff0c;如果你对投资理财、保险&#xff0c;英语学习、读书写作有兴趣&#xff0c;都欢迎来公众号【谭某人】与我交流&#xff0c;你总会有些收获。…

将本地项目上传到码云(gitee)远程仓库

前提条件&#xff1a; 1、本地电脑上已经安装了 git客户端&#xff0c;未安装的&#xff0c;具体安装过程可以参考此安装链接&#xff1a;https://blog.csdn.net/ezreal_tao/article/details/81609883 2、用户已经在gitee码云上注册完成 具体操作步骤&#xff1a; 1、登录码云…