当前位置:   article > 正文

【高并发系统设计理论】03 - 缓存_布隆过滤器过期策略

布隆过滤器过期策略

本节将介绍高并发下缓存相关问题和解决思想: 缓存读写策略、缓存高可用、缓存穿透


1. 缓存读写策略

对不同的业务场景,缓存的读写策略是不同的,以标准的 缓存 + 数据库 场景为例。我见过的不少项目是这样做的:

写操作:先更新 DB,再更新缓存
读操作:先查询缓存,缓存没命中就查 DB,并把结果写缓存

存在问题: 容易出现缓存和 DB 不一致。比如 A 线程先更新 DB, 紧接着 B 线程更新 DB。但是由于线程的切换是 “非公平” 的,迟迟没有轮到 A 线程执行,或者后续还有别的操作,最终 A 线程更新缓存的操作落后于 B 线程,导致数据不一致。

问题本质: 写数据库和写缓存,是两个独立的操作,没有并发控制(也可理解为没有事务控制) 想保证数据一致性,一定程度上写性能就会下降,下面将介绍高并发场景下的几种常用策略


这里介绍一种 旁路缓存(Cache Aside)策略

基本做法是先更 DB 再删缓存:

updateDB()
deleteCache()
  • 1
  • 2

旁路缓存基本满足大多数场景,但也可能会存在数据不一致问题。比如 DB 做了读写分离,可能主从同步还没有完成,读请求没有命中缓存再去 DB 查询时仍然是旧数据。

不过多数场景下,缓存在一定时间内和 DB 不一致是允许的。所以可以把缓存的过期时间设置短一些,比如 5~10 秒。或者是写操作并发不高时,也可以写缓存时加上 分布式锁。 还有通过消息队列或者订阅 binlog 异步更新缓存。

2. 缓存高可用

对于高并发系统而言,缓存命中率至关重要,特别是有的场景需要命中率维持在 99% 以上,分布式缓存的高可用常用方案主要有 3 大类: 客户端方案中间代理层方案服务端方案

  • 客户端方案 指在客户端配置好了多个缓存的节点,由客户端的读写策略、loadblance 策略来实现分布式,提高可用性。
  • 中间件代理方案 通过代理层实现高可用,比如阿里云的云 Redis 产品
  • 服务端方案 比如 Redis Sentinel

3. 缓存穿透

缓存穿透 指的是请求一个不存在的数据,导致每次请求都会命中数据库。一般来说会有 2 种解决方案:空值缓存布隆过滤器


空值缓存

Object data = getFromDB(key);
if (data == null) {
    // 为这个key设置空值缓存,假设默认过期时间为 10s
	cache.set(key, null, 10);
}
  • 1
  • 2
  • 3
  • 4
  • 5

问题: 如果攻击者大量请求不存在的 key,将导致缓存被大量吃满


布隆过滤器

1970 年布隆提出了一种布隆过滤器的算法,用来判断一个元素是否在一个集合中。这种算法由一个二进制数组和一个 Hash 算法组成。

我们把集合中的每一个值按照提供的 Hash 算法算出对应的 Hash 值,然后将 Hash 值对数组长度取模后得到需要计入数组的索引值,并且将数组这个位置的值从 0 改成 1。在判断一个元素是否存在于这个集合中时,你只需要将这个元素按照相同的算法计算出索引值,如果这个位置的值为 1 就认为这个元素在集合中,否则则认为不在集合中。

存在缺陷:

  1. 有一定错误几率的,比如会把不是集合中的元素判断为处在集合中;
  2. 不支持删除元素。

解决方案:

  1. 使用多个 hash 函数计算出多个 hash 值
  2. 不在存位,而是存数字,比如删除的时候就把计算出 hash 对应位置上的数减1,但是这样额外的空间消耗需要评估
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/466930
推荐阅读
相关标签
  

闽ICP备14008679号