From d4daff0f9b384c5c2aa0c923c15a31f024dfbbcf Mon Sep 17 00:00:00 2001 From: Deng Ming Date: Sat, 12 Mar 2022 15:53:19 +0800 Subject: [PATCH] add cache part1 --- cache/README.md | 130 ++++++++++++++++++++++++++++++++++ cache/img/cache_before_db.png | Bin 0 -> 7958 bytes cache/img/db_before_cache.png | Bin 0 -> 8006 bytes cache/img/db_remove_cache.png | Bin 0 -> 9435 bytes 4 files changed, 130 insertions(+) create mode 100644 cache/README.md create mode 100644 cache/img/cache_before_db.png create mode 100644 cache/img/db_before_cache.png create mode 100644 cache/img/db_remove_cache.png diff --git a/cache/README.md b/cache/README.md new file mode 100644 index 0000000..41dc3dd --- /dev/null +++ b/cache/README.md @@ -0,0 +1,130 @@ +# 缓存 + +解析:缓存的面试其实分成两大块: +- 缓存的基本理论 +- 缓存中间件的应用 + +这里我们讨论缓存的一些基本理论,缓存中间件 Redis 等,在 Redis 里面查看。 + +缓存的基本理论,目前来说考察比较多的是: +- 缓存和 DB 一致性的问题 +- 缓存模式 +- 缓存穿透、缓存击穿、缓存雪崩 + +首先针对缓存和 DB 一致性的问题,可以说这个问题是无最优解的。无论选择哪个方案,总是会有一些缺点。要想理解这个问题,核心是在于理解更新缓存和 DB 的先后顺序,在并发情况下,会出现哪些问题。 + +缓存模式主要是所谓的 cache-aside, read-through, write-through, write-back, refresh ahead 以及更新缓存使用到的 singleflight 模式。这些模式并不是银弹,如果说某个模式优于其它的模式,这就是在扯淡了。因此,选择何种缓存模式,也就是一个业务层面上考虑的问题,大多数时候,选取任何一种模式都不会有问题。 + +缓存穿透、击穿和雪崩,本质上就是一个问题:缓存没起效果。只不过根据不起效的原因进行了进一步的细分。 + +回答这一类的问题,都要详细解释每一种方案的优缺点,并且要总结出来“不是银弹”这个点。 + +首先要说三种常见但是必然会引起不一致的方案,这三种方案大同小异。面试的时候要记住为什么它们会引起不一致。因为很多时候没有完美方案,所以我们实践中还真有可能采用这三者之一: + +1. 先更新 DB,再更新缓存。不一致的情况: + 1. A 更新 DB,DB中数据被更新为1 + 2. B 更新 DB,DB中数据被更新为2 + 3. B 更新缓存,缓存中数据被更新为2 + 4. A 更新缓存,缓存中数据被更新为1 + 5. 此时缓存中数据为1,而DB中数据为2。这种不一致会一直持续到缓存过期,或者缓存和DB再次被更新,并且被修改正确; +![](img/db_before_cache.png) +1. 先更新缓存,再更新 DB。不一致的情况; + 1. A 更新缓存,缓存中数据被更新为1 + 2. B 更新缓存,缓存中数据被更新为2 + 3. B 更新 DB,DB中数据被更新为2 + 4. A 更新 DB,DB中数据被更新为1 + 5. 此时缓存中数据为2,但是DB 中数据为1。这种不一致会一直持续到缓存过期,或者缓存和DB再次被更新,并且被修改正确; +![](img/cache_before_db.png) +1. 先更新 DB,再删除缓存。不一致的情况; + 1. A 从数据库中读取数据1 + 2. B 更新数据库为2 + 3. B 删除缓存 + 4. A 更新缓存为1 + 5. 此时缓存中数据为1,数据库中数据为2 +![](img/db_remove_cache.png) + +所以本质上,没有完美的解决方案,或者说仅仅考虑这种更新顺序,是不足以解决缓存一致性问题的。 + +而大多数的方案,无非就是取舍上有一些不同。 + +而可能的方案,我比较喜欢的就两个: +- 第一个是负载均衡算法结合 singleflight +- 第二个是分布式锁。严格来说,分布式锁的方案,我一点都不喜欢,毫无技术含量 + +第一个方案,稍微有点奇诡。我们可以考虑对 key 采用哈希一致性算法来作为负载均衡算法,那么我们可以确保,同一个 key 的请求,永远会落到同一台实例上。然后结合单机 singleflight,那么可以确保永远只有一个线程更新缓存或者 DB,自然就不存在一致性问题了。 + +这个方案要注意的是在哈希一致性算法因为扩容,或者缩容,或者重新部署,导致 key 迁移到别的机器上的时候,会出现问题。假设请求1、2都操作同一个 key: +- 请求1被路由到机器 C 上 +- 扩容,加入了 C1 节点 +- 请求2被路由到了 C1 节点上 +- (以先写DB为例)请求1更新DB +- 请求2更新DB,请求2更新缓存 +- 请求1更新缓存 + +在这种情况下,你不管怎么搞都会出现不一致的问题。那么可能的解决方案就是: +- 要么在部署 C1 之前,在 C 上禁用缓存 +- 要么在部署 C1 之后,先不使用缓存,在等待一段时间之后,确保 C 上的迁移key的请求都被处理完了,C1 再启用缓存 + +分布式锁的方案就没什么好说的了,咔嚓一把分布式锁一了百了。分布式锁适用于写请求特别少的例子,因为读是没有必要加分布式锁的。读完全没有必要加分布式锁,即便此时有人正在更新缓存或者 DB,当前的请求要么读到更新前的,要么读到更新后的,不会有什么问题。 + +另外一个分布式锁方案的优化是在单机上引入 singleflight,确保一个实例针对一个特定的 key 只会有一个线程去参与抢全局锁。 + +还有一种思路是利用 CDS 接口,异步更新缓存,但是本质上,也是要忍受一段时间的不一致性。比如说典型的,应用只更新 MySQL,然后监听 MySQL 的 binlog,更新缓存。 + +## 面试题 + +### 如何解决缓存和 DB 的一致性问题 +分析:日经题,每次面,但凡简历上出现了缓存两个字眼,就会问。甚至于,只要面试官公司用了缓存,他们就会问。 + +缓存和 DB 数据一致性的问题,先说结论:没有完美的方案,无非就是取舍问题。 + +一般的思路就是,先指出,先更新 DB 还是先更新缓存,还是更新DB之后删除缓存的方案,本质上都有一致性的问题,从而强调,仅仅依靠缓存和DB是做不到一致性的,要结合别的组件。 + +然后回答两个方案: +- 分布式锁方案:该方案亮点在于强调可以引入单机 singleflight 来减少锁竞争; +- 结合负载均衡算法,可以利用哈希一致性负载均衡算法和单机上的 singleflight + +两个方案的本质都是确保只有一个线程操作特定的 key + +答:缓存和 DB 的一致性问题,没有什么特别好的解决方案,主要就是一个取舍的问题。 + +如果能够忍受短时间的不一致,那么可以考虑只更新 DB,等缓存自然过期。大多数场景其实没有那么强的一致性需求,这样做就够了。 + +进一步也可以考虑先更新 DB 再更新缓存,或者先更新缓存再更新 DB,或者更新 DB 之后删除缓存,都会有不一致的可能,但是至少不会比只更新 DB 更差。 + +另外一种思路是利用 CDC 接口,比如说监听 MySQL 的binlog,然后更新缓存。应用是只更新 MySQL,丝毫不关心缓存更新的问题。(引导面试官问 CDC 问题,或者 MySQL binlog,或者说这种模式和别的思路比起来有什么优缺点) + +至于说其它的比如说 cache-aside, write-through, read-through, write-back 也对一致性问题,毫无帮助。(引导面试官问之后几个 pattern) + +如果追求强一致性,那么可行的方案有两个: +- 利用分布式锁。在读上没必要加锁,在写的时候加锁。(面试官可能会进一步问,为什么读不需要加锁,很简单,在同一个时刻,有人更新数据,有人读数据,那么读的人,读到哪个数据都是可以的。如果写已经完成,那么读到的肯定是新数据,如果写没有完成,读到的肯定是老数据)。(刷亮点)一种可行的优化方案,是在单机上引入 singleflight。那么更新某个 key 的时候,同一个实例上的线程自己竞争一下,决出一个线程去参与抢全局分布式锁。在写频繁的时候,这种优化能够有些减轻分布式锁的压力。(实际上,写频繁的还要追求强一致性,还要用缓存简直无力吐槽) +- 另外一个方案是利用负载均衡算法和 singleflight。可以选择一种负载均衡算法,即一个 key 只会被路由到同一个实例上。比如说使用一致性哈希算法。结合 singleflight,那么可以确保全局只有一个线程去更新数据,那么自然就不存在一致性的问题了。(开始进一步讨论这种方案的细节,也可以等面试官问。面试官要是水平高,他自然就会意识到在扩容缩容,或者重启的时候,会有问题。要是面试官水平不高,他是意识不到的,哈哈哈,所以可以用来试探一下面试官的斤两) + + 这种方案的问题在于,在扩容、缩容、或者重启的时候,因为会引起 key 迁移到别的实例上,所以可能出现不一致的问题。在这种情况下,可以考虑两种方案。第一种方案是扩容或者缩容的时候在原本实例上禁用这些迁移 key 的缓存;另外一种方案是目标实例先不开启读这些迁移 key 的缓存,等一小段时间,确保原本实例上的这些迁移 key 的请求都被处理完了,然后再开启缓存。 + +#### 类似问题 +- 在使用了缓存的时候,你先更新缓存还是先更新 DB +- 要是先更新缓存成功,再更新 DB 失败会怎样 +- 要是先更新DB成功,但是更新缓存失败会怎样 +- 更新 DB 之后,删除缓存的做法有什么弊端?怎么解决这种弊端? + +### singleflight 是什么 +分析:本质上来说,singleflight 只是一个设计模式,你可以用于缓存,也可以用于别的方面。 +singleflight 是指,如果多个线程(协程)去做同一件事,那么我们可以采用 singleflight 模式,从多个线程里面挑出来一个去做,其余的线程就停下来等结果。 + +singleflight 在缓存里面主要用在更新缓存上,防止在缓存未命中的时候,多个线程同时访问 DB,给 DB 造成巨大的压力。 + +答:singleflight 是一种设计模式,使用这种设计模式,可以在我们更新缓存的时候,控制住只有一个线程去更新缓存。 + +不过,这里面强调的一个线程只是指同一个 key 只会有一个线程。因为我们并不会说更新不同的 key 也共享一个更新线程。 + +(亮点,要解释 singleflight 只在单机层面上,而不是在全局上)另外一个是,在分布式环境下,我们只做单机层面上的控制。也就是说,如果有多台机器,我们会保证一个机器只有一个线程去更新特定一个 key 的缓存。比如说,针对 key1,如果有三台机器,那么最多会有三个线程去更新缓存。 + +不做全局的原因很简单,在分布式环境下,数据库至少要能撑住这种多台机器同时发起请求的负载。而做全局的 singleflight 本质上就是利用分布式锁,这个东西非常消耗性能。 + +(如果是 Go 语言)在 Go 上,标准库直接提供了 singleflight 的支持。(这里要防面试官让你手写一个) + +#### 类似问题 +- 为什么用 singleflight +- 为什么 singleflight 只在单机层面上应用 +- 如果要在全局层面上应用 singleflight,怎么搞?其实就是加一个分布式锁,没什么花头 diff --git a/cache/img/cache_before_db.png b/cache/img/cache_before_db.png new file mode 100644 index 0000000000000000000000000000000000000000..563f0589bdd4dcff273f618049aff3841a474af0 GIT binary patch literal 7958 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 KFUn7ce)V4;0>5hj literal 0 HcmV?d00001 diff --git a/cache/img/db_before_cache.png b/cache/img/db_before_cache.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5e3274828d3362cac509ecd39f6bcb32a834c3 GIT binary patch literal 8006 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 SgLmJ+F(>zLD!)GSr@sPuDEfQ= literal 0 HcmV?d00001 diff --git a/cache/img/db_remove_cache.png b/cache/img/db_remove_cache.png new file mode 100644 index 0000000000000000000000000000000000000000..d6512378099b8f2847dee6fac508733e3601366c GIT binary patch literal 9435 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 literal 0 HcmV?d00001