缓存问题

为了能够对请求进行快速响应,出现了缓存。它能利用内存的高速读写性能来应付海量的查询请求。然而内存资源非常宝贵,将全部数据都放在内存显然是不切实际的。

目前都是采用内存和磁盘结合的方式,内存只存储热点数据,而 IO 设备存储全部的数据。本文将对缓存以及热点数据中存在的问题进行讨论。

缓存穿透

互联网应用中缓存的使用模型:

  1. 业务系统发起查询请求,判断缓存中是否有该数据。
  2. 如果缓存中存在,直接返回数据。
  3. 如果缓存中不存在,则再查询数据库,然后返回数据。
什么是缓存穿透

缓存中不存在该业务数据,会直接前往数据库中查询,但是数据根本不存在,数据返回也为空,这里称为缓存穿透。

缓存穿透的危害

如果还想请求查询压根就不存在的数据,那么这些海量请求都会落到数据库中,数据库压力过大会导致崩溃。

解决方案
  1. 缓存空数据

    之所以发生缓存穿透,是因为缓存中没有存储这些空数据的 key,导致这些请求全部打到了数据库上。

    我们可以稍微修改业务系统的代码,将查询结果为空的 key 也缓存到缓存中个,这样后续该 key 的请求就无需查询数据库了。

  2. 屏障 BloomFilter

    它需要在缓存之前加一道屏障,里面存储目前数据库中的所有 key。Redis 中有高级用法叫布隆过滤器。

当业务系统有查询请求的时候,首先去 BloomFilter 中查询该 key 是否存在。若不存在,则说明数据库也不存在该数据,因此缓存都不用查了。

两种方法的比较

对于一些恶意攻击,查询的 key 往往不同,而且数据极多。此时第一种方案就显得捉襟见肘了。所以对于空数据的 key 各不相同,key 重复概率低的场景而言,应该选择第二种方案。对于空数据的 key 数量有限,key 重复请求概率较高的场景而言,应该选择第一种方案。

缓存雪崩

什么是缓存雪崩?

通过上文可知,缓存其实扮演了一个保护数据库的角色。它帮助数据库抵挡了大量的查询请求,从而避免脆弱的数据库受到伤害。

如果缓存因为某种原因发生了宕机,那么原本被缓存抵挡的海量请求就会直接涌向数据库,数据库不堪重负就会崩溃,这就是缓存雪崩。

解决方案
  1. 使用缓存集群,保证缓存高可用。也就是在发生雪崩之前,做好防护。

  2. Hystrix

    Hystrix 是一款开源的放雪崩工具,它通过熔断,降级,限流三个手段来降低雪崩发生后的损失。Hystrix 一旦发现当前服务的请求失败率达到预设的值后,Hystrix 会拒绝随后该服务的所有请求,直接返回一个预设的结果,这就是熔断。过一段时间,Hystrix 会放行一部分请求,在此统计请求失败率,如果符合预设值,会打开限流开关,如果失败率仍然很高,就会拒绝该服务所有请求,这就是限流。Hystrix 向被拒绝的请求返回预设结果被称为降级。

缓存击穿

什么是缓存击穿?

我们一般都会给缓存设定一个失效时间,过了时间后,该数据会被删除,从而在一定程度上保证数据的实时性。

对于一些请求量极高的数据而言,一旦过了有效时间,此刻会有大量的请求落在数据库上,从而可能会导致数据库崩溃。

!

从缓存失效到查询数据库后更新缓存的时间,肯能会有许多请求同时到达,此时,它们都会查询数据库,而且会重复更新缓存。

解决方案
  1. 互斥锁

    可以使用缓存自带的锁机制,当一个数据库查询请求发起时,就将该缓存中该数据上锁。此时到达缓存的其他查询无法查询该字段,从而被阻塞。直到第一个请求完成数据库查询并更新缓存后,释放锁。

热点数据集中失效问题

什么是热点数据集中失效的问题?

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

解决方案

设置不同的失效时间

  1. 当我们向缓存中存储这些数据的时候,可以将他们的缓存失效时间错开。这样能够避免同时失效。比如在基础时间上加一个随机数,从而将缓存的失效时间错开。
  2. 互斥锁。
posted @ 2020-01-31 16:45  当年明月123  阅读(157)  评论(0编辑  收藏  举报