How to choose between cache-aside, read-through, write-through, client-side, and distributed caching strategies 正如我们在最近所提到的 文章,我们很高兴Pekka Enberg决定写 我们很自豪能够赞助这三章。 为什么要隐藏数据? 一本关于延迟的书 获取Latency书摘要PDF 获取Latency书摘要PDF 获取Latency书摘要PDF 此外,Pekka刚刚在一本书中分享了该书的关键摘要。 (现可按要求提供) 关于构建低延迟应用程序的硕士课程 让我们继续我们的 本书的摘要有更多来自Pekka的缓存章节.它在出版商的许可下重印在这里。 延迟 」 将缓存添加到您的应用程序时,您必须首先考虑您的缓存策略,该策略决定从缓存和底层的备份库(例如数据库或服务)中如何读取和写入。 换句话说,当您的应用程序从缓存中查看一个值,但该值不在那里或已过期时,缓存策略命令无论是您的应用程序还是从备份存储中获取该值的缓存。 缓存与缓存 缓存侧缓存可能是你会遇到的最典型的缓存策略. 当有缓存攻击时,数据访问延迟是由通信延迟主导的,这通常很小,因为你可以在缓存服务器上或甚至在应用程序内存空间中接近缓存。 然而,当有缓存漏洞时,在缓存侧缓存时,缓存是应用程序更新的被动存储,也就是说,缓存只是报告漏洞,应用程序负责从备份存储中获取数据并更新缓存。 图 1 显示了在行动中缓存的例子,一个应用程序通过缓存密钥从缓存中查看一个值,这决定了应用程序感兴趣的数据。 如果密钥存在于缓存中,缓存将返回与密钥相关的值,该值可以被应用程序使用,但是,如果密钥不存在或已在缓存中过期,我们有一个缓存漏洞,该应用程序必须处理。 假设您正在缓存用户信息并使用用户 ID 作为搜索密钥。在这种情况下,应用程序会通过用户 ID 执行查询,从数据库中读取用户信息。从数据库中返回的用户信息然后转换为您可以在缓存中存储的格式。 缓存侧面缓存很受欢迎,因为很容易设置一个缓存服务器,如Redis,并使用它来缓存数据库查询和服务响应。 缓存侧面缓存,缓存服务器是被动的,不需要知道你使用哪个数据库或结果是如何将缓存的。 在许多情况下,缓存侧缓存是减少应用程序延迟的简单有效方法. 您可以通过在应用程序附近的缓存服务器中存储最相关的信息来隐藏数据库访问延迟。 例如,如果您有多个同时阅读器在缓存中寻找一个密钥,则需要在应用程序中协调如何处理同时缓存漏洞;否则,您可能会最终获得多个数据库访问和缓存更新,这可能会导致随后的缓存搜索返回不同的值。 然而,在缓存旁边缓存中,你会失去交易支持,因为缓存和数据库彼此不认识,并且它是应用程序协调更新数据的责任。 最后,缓存旁边缓存可能会有显著的尾巴延迟,因为一些缓存搜索体验数据库阅读延迟在缓存错误时。 通过缓存阅读 通过读取缓存是一种策略,与缓存旁边缓存不同,缓存是缓存错误时的活跃组件。当出现缓存错误时,通过读取缓存会尝试自动从备份库读取密钥的值。延迟类似于缓存旁边缓存,尽管备份库的检索延迟是从缓存到备份库,而不是从应用程序到备份库,这可能较小,取决于您的部署架构。 图 2 显示了在动作中进行读取缓存的例子。应用程序对一个密钥进行缓存搜索,如果有缓存漏洞,缓存会对数据库进行读取以获取密钥的值。 通过读取缓存更为复杂,因为缓存需要能够读取备份库,但它还需要将数据库结果转换为缓存格式.例如,如果缓存库是SQL数据库服务器,则需要将查询结果转换为JSON或类似格式以便在缓存中存储结果。 然而,由于缓存协调更新,而数据库通过读取缓存读取,它可以为应用程序提供交易性保证,并确保在同时错过缓存时保持一致性。 当然,同样的尾巴延迟警告也适用于通过读缓存,就像它们适用于缓存旁边缓存一样。一个例外:作为活跃组件,通过读缓存可以更好地隐藏延迟,例如,刷新前缓存。 通过缓存写作 在这种情况下,缓存提供了更新应用程序可以召唤的密钥的值的界面。在缓存旁边缓存的情况下,应用程序是唯一与备份存储通信的,因此更新缓存。 通过编写的缓存是将缓存更新立即传递到备份商店的策略. 每当缓存被更新时,缓存会同步更新缓存商店的缓存值。 通过编写的缓存的写入延迟是由向缓存商店的写入延迟主导的,这可能是显著的。 如图3所示,应用程序使用缓存提供的接口更新缓存,使用密钥和值对。 缓存更新其状态以新的值,更新数据库以新的值,并等待数据库承诺更新,直到承认缓存更新到应用程序。 通过编写的缓存旨在保持缓存和备份存储的同步性. 然而,对于非交易缓存,缓存和备份存储在存在错误的情况下可能会失灵。 例如,如果写到缓存成功,但写到备份存储失败,两者将失灵。 与通过读取缓存一样,通过写入缓存假定缓存可以连接到数据库并将缓存值转换为数据库查询,例如,如果您正在缓存用户数据,用户 ID 作为密钥,而 JSON 文档代表值,缓存必须能够将用户信息的 JSON 表示转换为数据库更新。 通过编写缓存,最简单的解决方案通常是将 JSON 存储在数据库中。通过编写缓存的主要缺点是与缓存更新相关的延迟,这基本上相当于数据库委托延迟。 字幕背后Caching 换句话说,在写后缓存中,缓存可能在更新备份存储之前接受多个更新,如图4所示,缓存在更新数据库之前接受三个缓存更新。 写后缓存的写延迟低于写后缓存的写延迟,因为后备存储被非同步更新,也就是说,缓存可以立即识别写到应用程序,导致写后延迟较低,然后在背景中执行后备存储更新。然而,写后缓存的缺点是您失去交易支持,因为缓存不能再保证缓存和数据库是同步的。 客户端缓存 客户端缓存策略意味着在应用程序中的客户端层中有缓存,尽管 Redis 等缓存服务器使用内存缓存,但应用程序必须通过网络进行通信以通过 Redis 协议访问缓存。 如果应用程序是一个在数据中心运行的服务,那么缓存服务器对于缓存是很好的,因为数据中心内部的网络周期是快速的,缓存的复杂性在缓存本身。 通过客户端缓存,从延迟角度来看,读后缓存和写后缓存的组合是最佳的,因为读后缓存和写后缓存都快。当然,您的客户端通常无法直接连接到数据库,而是通过代理或API服务器间接访问数据库。 对于许多需要低延迟客户端缓存的应用程序,本地复制方法可能更实用,但对于简单的阅读缓存,客户端缓存可以是实现低延迟的好解决方案。 分布式缓存 到目前为止,我们只讨论了缓存,就好像存在一个单一的缓存实例一样。例如,您使用应用程序内缓存或单一的 Redis 服务器来缓存来自 PostgreSQL 数据库的查询。 有了这种分布式缓存,你有许多缓存实例,无论是独立工作还是在一个缓存集群中。 与分布式缓存,你有许多相同的并发症和考虑,如在第4章关于复制和第5章关于分区讨论的。 总的来说,分布式缓存是缓存,分区和复制的好处和问题的交叉点,所以要小心你是否正在进行。 」 为了继续阅读, 从 ScyllaDB 或 . 免费下载第3章 延迟摘要 购买曼宁的完整书籍 关于Cynthia Dunlop Cynthia 是 ScyllaDB 的内容策略高级总监,她已经写了 20 多年的软件开发和质量工程。