缓存穿透等概念

缓存的处理流程

请求数据时,先从缓存中取数据,取到就返回结果,没有则从数据库中取,数据库取到后更新缓存,并返回结果,数据库中没有数据,那就返回空结果。
在这里插入图片描述

1. 缓存穿透

通俗地说缓存穿透就是用户对不存在的数据发起请求.比如用户请求 id = -1 的数据,缓存中当然不会有这条数据, 那就只能去数据库查找,而数据库也不会有,只能全表扫描. 当用户不断发起该类请求,那就很可能是攻击者, 攻击会导致数据库压力过大.
解决方法:

  • 对请求进行过滤校验, 对 id<=0 的不合法请求直接拦截, 可使用布隆过滤器.
  • 对不存在的数据缓存一个空数据,如果在缓存和数据库中都找不到请求的数据,就返回这个空数据.

Reference: 布隆过滤器

原理是对一个key进行k个不同hash算法获取k个值,在比特数组中将这k个值在数组中的下标置为1,查的时候如果某个key的在数组中k个位置都为1,那么布隆过滤器判断该key可能存在(并不一定存在)。
布隆过滤器可能会误判,如果它说不存在那肯定不存在,如果它说存在,那数据有可能实际不存在.

例如: 比特数组 Bytearray 大小为 16, 则其原始数据为 [ 0000 0000 0000 0000 ].

  • 添加:
    对 “Hello” 经过 2 个不同hash算法获得在该数组中两个下标(3,5), 则比特数组改变为 [0001 0100 0000 0000], 下标位置Bytearray[3] = 1, Bytearray[5] = 1.
  • 查找:
    对 “Hello” 经过 2 个不同hash算法获得值为(3,5),去查找Bytearray[3] 和 Bytearray[5] 的值, 都为1, 则可能存在. 因为下标 Bytearray[3] 和 Bytearray[5]等于1可能是其他元素经过hash 留下的标记, 故 “Hello” 实际可能不存在.

由上可知,如果每个元素k次hash后在数组中的下标都不相同, 则可认为布隆过滤器的准确率为 100%.

Bloom Filter的核心思想
  1. 多个hash,增大随机性,减少hash碰撞的概率.
  2. 扩大数组范围,使hash值均匀分布,进一步减少hash碰撞的概率.

Google 的开源工具 Guava 中包含了 Bloom Filter 实现,另外传统的布隆过滤器只能添加数据不能删除数据,其变种 Counting Bloom Filter 给Bloom Filter增加了删除操作,代价是多占用几倍存储空间


Counting Bloom Filter 的思想是将标准 Bloom Filter 位数组的每一位扩展为一个小的计数器(Counter),在插入元素时给对应的 k(k为哈希函数个数)个 Counter 的值分别加1,删除元素时给对应的 k 个Counter 的值分别减1

2. 缓存击穿

缓存击穿是指缓存中没有但数据库中有的单条数据(通常由缓存过期造成)被并发查询,并发请求非常多,同时读缓存没有读到又同时去读数据库,造成数据库压力过大.
解决方法:

  • 设置热点数据永不过期.
  • 加互斥锁,读数据库时需要获取锁,一条请求拿到锁之后读取数据并更新缓存,其他未获得锁请求延时后再去读取缓存数据.

3. 缓存雪崩

缓存雪崩发生时说明缓存中大批量的数据过期,而查询量巨大,请求直接到达数据库,造成数据库压力剧增.
解决方法:

  • 随机设置缓存数据过期是时间,防止大规模缓存数据同时间过期.
  • 设置热点数据永不过期.
  • 分布式部署的缓存将热点数据均匀分布在不同的缓存数据库中.

4. 缓存一致性

要求数据库数据更新时缓存中的数据也能实时更新.
解决方法:

  • 数据库更新时立即去更新缓存.
  • 数据库更新前先删除缓存,更新完成后再次删除缓存,也就是延迟双删的策略。外部请求没有命中缓存则会查询数据库,查到数据后将其更新到缓存中,则自动保持了一致性.
  • 为缓存设置一个过期时间,读缓存数据前判断缓存是否过期,过期了则从数据库中查询数据,进行缓存更新.

有兴趣的读者可以参考 缓存一致性设计方案

5. 缓存清理策略

  • FIFO(先进先出) :最先进入缓存的数据在缓存空间不足时被优先清除.
  • LFU(最少使用) :无论数据是否过期,根据其使用的次数判断,清除使用次数最少的数据.
  • LRU(最近最少使用):
    无论数据是否过期,根据数据最后一次被使用的时间戳,清除最远使用时间戳的数据.

    实现:
    LinkedHashMap 中的 accessOrder 属性设置为 true 时将根据元素的访问顺序将最近访问的数据放在双向链表尾部, 同时重写其 removeEldestEntry() 方法指定数据淘汰条件,即可实现LRU.

6. 缓存分类

6.1.本地缓存

缓存数据保存在单个服务器内存中,各个服务器之间缓存的数据相互独立

  • 优点:读取速度快
  • 缺点:分开存储可能出现一台应用服务器的数据有更新,而其他服务器数据没有更新,导致数据不一致的问题.

6.2.集中式缓存

缓存数据保存在专门的缓存服务器中,应用服务器通过网络请求从缓存服务器获取缓存数据

  • 优点:集中管理缓存,保证数据一致性
  • 缺点:网络请求需要消耗时间,读取频繁的话网络请求消耗的时间成本可能比将数据从数据库读取出来的成本还要高
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
缓存击穿、缓存穿透缓存雪崩都是与缓存相关的问题,它们可能导致系统性能下降甚至宕机。下面分别解释这三个概念: 1. 缓存击穿(Cache Breakdown):当一个缓存键(key)对应的数据在缓存不存在,但是对该数据的并发请求非常多时,这些请求会直接访问数据库或其他数据源,导致数据库负载过高。这种情况下,缓存起不到应有的作用,而是成了一个瓶颈。 2. 缓存穿透(Cache Penetration):当一个缓存键对应的数据在缓存不存在,并且对该数据的请求非常频繁时,大量的请求会直接穿透缓存访问数据库或其他数据源。这种情况下,由于缓存无法命,数据库负载会剧增,可能导致数据库压力过大甚至崩溃。 3. 缓存雪崩(Cache Avalanche):当缓存的大量数据同时失效或过期时,在缓存重新加载数据的过程,大量并发请求会直接访问数据库或其他数据源。这种情况下,数据库负载会急剧增加,可能导致系统崩溃。缓存雪崩通常是由于缓存的数据过期时间设置不合理或者缓存服务器故障等原因引起的。 为了避免以上问题,可以采取以下措施: 1. 设置合理的缓存过期时间,避免缓存数据同时失效。 2. 使用互斥锁或分布式锁,确保只有一个请求能够从数据库加载数据。 3. 引入热点数据预加载,提前将热点数据加载到缓存,减少缓存穿透的可能性。 4. 使用多级缓存架构,将请求分散到不同的缓存节点,降低单个缓存节点的压力。 5. 监控缓存率和缓存服务器的状态,及时发现和解决问题。 通过合理的设计和有效的监控,可以有效地避免缓存击穿、缓存穿透缓存雪崩等问题,提升系统的性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值