3

Uber是如何花费巨大精力实现缓存精确失效?

 6 months ago
source link: https://www.jdon.com/72634.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Uber是如何花费巨大精力实现缓存精确失效? - 极道

这篇文章介绍了Uber内部分布式数据库Docstore的架构、挑战以及他们构建的集成缓存解决方案CacheFront。文章详细介绍了CacheFront的设计、特性和实现,以及对最终结果的评估。通过CacheFront,Uber成功解决了在Docstore上扩展读取工作负载的挑战,并取得了显著的性能提升和资源节约。

要点:
1、Uber 的 Docstore 是一个内部分布式数据库,存储数十 PB 的数据并处理数千万个请求,是 Uber 最大的数据库引擎之一。

2、为了应对大规模低延迟读取需求,Uber 开发了集成的缓存解决方案 CacheFront for Docstore,以降低数据库引擎层的资源分配,并改善 P50 和 P99 延迟。

3、CacheFront 通过缓存预留策略、利用变更数据捕获和流服务 Flux、比较缓存等功能,提供了强一致性的缓存解决方案,并成功降低了数据库引擎的负载,实现了低延迟读取请求的需求。

缓存读取
CacheFront 使用缓存预留策略来实现缓存读取:

  1. 查询引擎层收到多一行的读取请求
  2. 如果启用了缓存,请尝试从 Redis 获取行;将响应流式传输给用户
  3. 从存储引擎检索剩余行(如果有)
  4. 使用剩余行异步填充 Redis
  5. 将剩余行流式传输给用户

缓存失效
“计算机科学中只有两件难事:缓存失效和命名。” 
——菲尔·卡尔顿

如果没有任何显式缓存失效,缓存条目将在配置的 TTL(默认情况下为 5 分钟)内过期。虽然这在某些情况下可能没问题,但大多数用户希望更改的反映速度比 TTL 更快。默认的 TTL 可以降低,但这会降低我们的缓存命中率,而不会显着提高一致性保证。

1、有条件更新
Docstore 支持条件更新,可以根据过滤条件更新一行或多行。
例如,更新指定地区所有连锁餐厅的假期安排。由于给定过滤器的结果可能会更改,因此我们的缓存层无法确定哪些行将受到条件更新的影响,直到数据库引擎中更新了实际行。

2、利用变更数据捕获CDC 来使缓存失效 
为了解决这个问题,我们利用了 Docstore 的变更数据捕获和流服务 Flux。Flux 跟踪存储引擎层中每个集群的MySQL binlog事件,并将事件发布到消费者列表。Flux 为 Docstore CDC(更改数据捕获)、复制、物化视图、数据湖摄取以及验证集群中节点之间的数据一致性提供支持。 

3、在查询引擎和 Flux 之间删除重复的缓存写入
上述缓存失效策略有一个缺陷。由于写入在读取路径和写入路径之间同时发生在缓存中,因此我们可能会无意中将过时的行写入缓存,从而覆盖从数据库检索到的最新值。

为了解决这个问题,我们根据 MySQL 中行集的时间戳来删除重复写入,这实际上作为其版本。时间戳是从 Redis 中的编码行值中解析出来的。

4、更强的点写入一致性保证
虽然 Flux 允许我们比仅仅依赖 Redis TTL 来使缓存条目失效更快,但它仍然为我们提供了最终一致性语义。然而,某些用例需要更强的一致性,例如读自己写,因此对于这些场景,我们向查询引擎添加了专用 API,允许用户在相应的写入完成后显式使缓存的行无效。

更多细节点击标题


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK