“缓存穿透”、“缓存击穿”和“缓存雪崩”的概念和解决办法

2019年9月15日 评论

一、缓存

缓存的作用一般是为了减轻数据库压力设计的,因为数据都是读写磁盘,当并发量大的时候,磁盘IO可能跟不上并发量。而缓存一般设计都是放在内存中的,最常见的例如redis和memcached,都是把数据都缓存在内存中。读写内存的速度比磁盘快很多,因此把常用的数据都放到内存中做缓存可以给数据库减轻很大的压力。

一个正常的缓存处理流程为:

  1. 先判断缓存中是否存在数据,如果缓存存在数据,直接读缓存中的数据。
  2. 如果缓存不存在,从数据库读数据。
  3. 如果数据库中存在数据,返回数据库中的数据并写到缓存。
  4. 如果数据库中也不存在数据,直接返回。

“缓存穿透”、“缓存击穿”和“缓存雪崩”的概念和解决办法

而作为缓存系统,需要考虑的几个问题是:缓存穿透、缓存击穿和缓存雪崩。

二、缓存穿透

缓存穿透:查询一个数据库不存在的数据,因为数据都不存在,所以缓存中也不存在,请求会直接去数据库中查询,这种情况就产生了缓存穿透。

例如对一个只含非负整数的表中查询id = -1的记录,缓存中不存在数据,所以每次都会请求数据库。当有攻击者恶意使用这种方式频繁请求数据时,会给后端数据库造成极大的压力。

解决方案:

  1. 增加数据校验,直接过滤掉明显不存在的数据。这里一般采用布隆过滤器,预先生成所有可能的数据的bitmap,请求数据库前先在过滤器中查找,过滤掉不可能的数据。
  2. 对不存在的值也设置缓存,在数据库中查询到不存在的数据之后在缓存中添加一个key=null的值。

三、缓存击穿

缓存击穿:某个key缓存在某一时刻失效,由于请求量特别大,导致这一时刻的所有请求同时都直接请求数据库,给数据库带来巨大压力。

解决方案:使用互斥锁或者其它方法锁住这个key(单例模式),当有请求已经在查询这个key时,等待请求,这个请求完成后数据写入缓存再从缓存中读取数据。

四、缓存雪崩

缓存雪崩:给一些键值设置了过期时间,同一时刻这些数据同时失效,请求直接到达数据库。

解决方案:

  1. 和缓存击穿一样,使请求单例执行。
  2. 不要给缓存的过期时间都设置成一样的,设置超时事件的时候加上一个随机时间作为时间。

缓存雪崩和缓存击穿其实一样,缓存击穿时缓存雪崩的一个特例。

两者的区别:缓存雪崩是指多个缓存数据同时失效,而缓存击穿特指某一个数据失效。

如何通过原始套接字修改IP数据包头 编程语言

如何通过原始套接字修改IP数据包头

背景:我们的设备上有个链路探测的功能,会定时请求公网的某个IP地址,以探测网络是不是连通的。具体的做法是会使用icmp或dns探测远端服务器,看请求能否正常响应,如果有响应,则认为链路正常,否则则认为...
给socket分配随机端口 C/C++

给socket分配随机端口

客户端的socket不需要手动执行bind绑定地址,但这不意味着客户端socket真的不需要绑定端口,实际上是内核它帮我们做了这个操作,在执行connect时,内核发现没有绑定端口,就会自动选择一个合...
vector中emplace_back方法的用途 C/C++

vector中emplace_back方法的用途

在写代码的过程中,CLion提醒我把push_back方法替换成emplace_back方法: 代码中我的想法是使用vector创建一个二维数组,并提前分配好空间,避免后序频繁扩容增加时间复杂度。 e...
匿名

发表评论

匿名网友