RavenDB 中的缓存

一般来说,从主存储器中检索数据的速度大约是从固态驱动器中检索数据的四倍,而固态驱动器又是从网络中的服务器检索数据的大约 150 倍。这些值可能会有很大差异,但可以肯定的是,数据的来源会显着影响检索速度。

缓存是将检索到的数据的副本临时存储在更快速访问(更低延迟)的位置(称为缓存)的过程。它用于通过允许从缓存提供对相同数据的后续请求比从原始源快几个数量级来加速应用程序。

 

数据库缓存失效

虽然存储数据很简单,但决定何时保留数据可能是一个相当大的挑战。

当本地存储的数据不再匹配原始源的相应数据时,就说它已经过时了。据说仍然是最新的数据是新鲜的。根据具体情况,陈旧数据可以是从应用程序中断到不那么重要的任何数据,并且在变得陈旧之前可以安全地保存数据的时间量同样是可变的。 

考虑软件公司数据库中的数据:

  • 2020 年 7 月的购买数量永远不会改变。
  • 公司文案的薪水会时常变动。
  • 有效支持票的数量会经常变化。

在任何使用动态数据的情况下,您都需要在某个时间点刷新缓存中的数据——这个过程称为缓存失效。

无效的方法有:

  • 清除 - 从缓存中删除数据。
  • 刷新 - 从原始源获取数据以更新缓存的数据。
  • Ban  – 标记缓存中的数据,以便在请求时调用原始源并将最新数据返回给客户端并用于更新缓存。

但是您如何确定将数据保存在缓存中的时间?您如何知道何时需要返回原始源以获取最新版本? 

上述方法的替代方法可以提供答案。

  • 生存时间 (TTL) – 计数器或时间戳等控件可用于指示缓存数据的生命周期。当时间到期时,数据将从缓存中清除。
  • 选择性缓存——而不是将所有结果存储在缓存中,这只会保留不太可能改变的信息,或者新鲜度不重要的信息。
  • 请求验证- 每当请求缓存数据时,都会联系原始源以查询自上次读取数据以来数据是否已更改。

数据库缓存的好处

缓存使数据访问更快,但是在使用数据库的应用程序的上下文中这实际上转化为什么?这是一个更全面的外观:

  • 更快的读取。 
  • 增加吞吐量。
  • 减少数据库负载——您只需检索一次数据,而不是多次,因此您的数据库可以自由地做其他事情。
  • 降低成本,减少网络使用量,减少 I/O。
  • 更可靠的性能——无网络问题。
  • 没有瓶颈——需要多次检索某条数据不再是系统的负担。

数据库如何处理缓存数据

在数据库中缓存数据有两种主要方法:

  1. 将数据集存储在内存而不是服务器端的磁盘中。
  2. 在客户端缓存查询结果。

大多数受人尊敬的数据库系统将提供内存选项:

  • Oracle 有一个“内存数据库缓存”产品选项。
  • MySQL 有一个“MEMORY Engine”,您需要手动启用和配置它,它带有各种警告。 
  • MongoDB 尽可能将工作数据集存储在内存中,如果您有这些查询的索引,则从那里提供查询服务。
  • RavenDB 类似地将您的数据集尽可能地存储在内存中,并从那里提供查询服务。 

客户端结果缓存不太常见:

  • Oracle 缓存查询结果。
  • MySQL一个名为 Query Cache 的功能,但由于可伸缩性问题,他们不得不将其删除。
  • MongoDB 不缓存查询结果。
  • RavenDB 缓存查询结果。

还有一种在数据库外部进行缓存的策略。当数据库变慢时,一个常见的解决方案是使用 Redis。

Redis 作为缓存

Redis 是一种快速的内存数据库,通常用作缓存层。它可以放在数据存储之前,以加快常见查询并使应用程序更具响应性。将一个数据库放在另一个数据库前面可能看起来不直观——您只是添加了额外的步骤——但它比让您的开发人员花费 100 个小时来开发、优化和重构您的原始数据库更便宜、更容易。

关系数据库模型是在 70 年代设计的,当时数据高度结构化并适合软盘。尝试将大量非结构化或半结构化数据组织和存储为关系格式是很困难的,并且可能需要大量的专业知识、时间和工作来优化。因此,Redis 被广泛用于这些数据库,以至于它经常在项目中包含它甚至是必要的。

然而,关系数据库并不是唯一的罪魁祸首。任何试图做它不适合的工作的数据库都可以从 Redis 中受益。例如,MongoDB 的主从架构只允许一个节点接受写入,然后将接受的数据分发给其他节点。这可能会导致大规模性能不佳,并且可以使用 Redis 来缓解该问题。

在数据库中寻找什么

缓存是一个深刻而复杂的话题,有很多厚厚的教科书都写过它。它真的 很有用,但你真的 不想自己实现它。 

理想情况下,数据库系统应该在客户端和服务器端内置自动缓存行为,同时允许足够的可选定制以针对特定用例进行优化。(一种不太关心数据新鲜度的缓存形式可能会极大地提高一个系统的性能,同时完全破坏另一个系统。)

此外,数据库应该具有足够的性能和足够好的扩展能力,以至于它不需要在它前面设置缓存层。

考虑到这一点,让我们看看 RavenDB 如何处理缓存。

RavenDB 中的缓存

RavenDB 是一个快速的分布式文档数据库,专为 OLTP 工作负载而设计。它自动化了许多正常的优化过程,如索引、压缩,当然还有缓存。它应该在任何规模上都具有足够的性能,以至于它永远不需要像 Redis 这样的外部缓存层。

如前所述,RavenDB 尽可能在服务器端将您的工作数据集存储在内存中。我们真的不需要考虑这一点——这一切都是自动化的,并且在没有任何用户参与的情况下加快了您的查询速度。

客户端缓存值得深入研究。

您的客户端应用程序和 RavenDB 之间的通信是通过 HTTP 请求进行的,并通过称为 Document Store 的客户端 API 对象进行管理。  

RavenDB 利用现有的 HTTP 缓存功能和 Etags 进行请求验证。

HTTP 缓存和 Etag

在 Internet 上使用的最常见的缓存类型是HTTP缓存。无需过多详细介绍 HTTP 的工作原理,基本上,它是一种基于文本的协议,用于通过网络传输数据。 

HTTP 请求和响应具有标头字段,这些字段是与数据一起发送的字符串列表。标头字段可以有各种用途,其中一些是缓存。

ETags,(实体标签的缩写)是 HTTP 响应标头。检索到的资源有唯一标识符。如果该资源发生更改,ETag 将有所不同。 

每当发出与缓存中的先前请求匹配的 GET 请求时,该请求的存储 ETag 就会发送到服务器。如果服务器上的 ETag 相同,则服务器将简单地响应资源没有更改(304 Not Modified)。在这种情况下,客户端将知道本地存储的数据仍然是新鲜的,并将按原样使用它。如果服务器上的 ETag 不同,服务器将连同新的 ETag 一起发送新数据。

RavenDB 中的 HTTP 缓存细节

在 RavenDB 中,几乎所有的读取操作都会生成一个 ETag,而不仅仅是查询。例如,加载一个文档也会生成一个 ETag。有些东西没有被缓存,例如总是不同的信息,如系统统计信息和调试端点,以及附件,它们对于缓存来说可能太大并且处理方式完全不同。 

对服务器的所有请求和响应都缓存(已经解析)在文档存储中。使用相同文档存储的所有会话将共享相同的缓存。

当服务器收到带有 ETag 的请求时,它会遵循优化的代码路径来检查请求的结果是否发生了变化。

RavenDB 在后台自动处理客户端缓存。从用户的角度来看,它是完全不可见的,但在某些情况下了解它的工作原理可以让您进一步利用它。

例如,任何使用DateTime.Now的查询通常都是唯一的,不能通过在客户端缓存来优化。但是,如果您使用DateTime.Today来自同一天的任何相同查询将产生相同的结果。如果您需要比每天更好的粒度,使用当前小时或分钟也足以让您的查询选择从缓存中受益。 

缓存的默认大小取决于您的系统规格,并且可以根据需要更改最大大小。可以为会话全局禁用自动缓存,强制所有请求转到服务器。

积极缓存

上述 HTTP 缓存行为可确保您获得的数据是最新的。在数据的新鲜度不是绝对关键的情况下,RavenDB 提供了另一种不需要在读取时访问服务器的选项。此选项称为Aggressive Caching,是 RavenDB 独有的。

激活积极模式后,每当第一次发出请求时,客户端都会打开与服务器的连接,并告诉服务器让其知道是否对数据进行了任何更改。(注意:通知是针对服务器上的任何更改发送的,而不仅仅是对先前请求的数据的更改。)

当客户端重复请求数据时,如果服务器自上次请求信息以来没有报告任何更改,则客户端将使用缓存的数据而不联系服务器。

如果服务器报告了更改,并且该信息的本地副本早于该通知,则该请求将遵循 RavenDB 的常规缓存行为,然后将更新缓存数据的时间戳。

简而言之:积极模式允许数据库在客户端使缓存无效。

这允许更快的查询,同时仍确保您获得最新的数据。那么为什么不默认开启呢?因为服务器上的数据可能已经改变了,但是客户端可能还没有被通知。使用常规的 RavenDB 客户端缓存,您将不会获得过时的信息,因为您将始终首先验证缓存的数据。您需要专门激活积极模式,因为它可能会导致您使用过时的数据。

集群中的缓存行为

RavenDB 建议部署在至少 3 个节点的集群中,以确保高可用性。不同的节点有不同的 URL,所以同一个请求会被单独存储在不同服务器的缓存中。没有跨节点缓存,但实际上,由于 RavenDB 在集群中分配请求的方式,您通常会使用您的请求访问同一台服务器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千源万码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值