缓存与索引的区别

24
什么是缓存解决方案和索引解决方案之间的真正区别?在我看来,索引解决方案实际上是具有运行搜索查询能力的缓存(例如:Elasticsearch)。在同一个项目中使用缓存解决方案和索引解决方案是否有任何真正的原因,或者索引解决方案是否基本上使任何其他缓存都变得多余?
例如:假设我使用NEST进行Elasticsearch,它会存储并返回POCO; 如果我然后查询Elasticsearch并将POCO返回给我,那么这是否被认为是使用从Elasticsearch返回的缓存对象?
目前,我使用ICacheManager接口将数据存储在缓存中,类似于此:
return CacheManager.Get(cacheKey, () =>
{
    // return something...
});
这会在ElasticSearch中是否变得多余?
编辑
谢谢大家的回答。我完全知道缓存是什么,也已经理解了文本搜索索引背后的一般思想,所以我只是想知道索引是否已经兼作缓存,从而使其他任何缓存都变得多余。毕竟,我不想在内存中保留2个缓存(例如:ElasticSearch + Redis),一个就足够了。不过现在我想我有了更好的想法; 尤其是当我意识到并非所有字段都始终存储在索引中,因此我们无论如何需要从缓存或直接从数据库获取对象-至少在某些情况下要这样做。谢谢大家!

2
考虑到这个问题已经超过一年了,我很想知道您是否已经探索了ES作为缓存解决方案。 - Mark
3个回答

27
缓存的整个目的是尽快返回已经请求过的数据。缓存的一个限制是它们不能太大,否则查找时间会增加,从而打败了首先拥有缓存的目的。话虽如此,如果您计划在数据库中拥有几百万/十亿条记录,将所有记录索引起来可能并不困难,但将它们全部缓存起来却很难,尽管由于RAM变得越来越便宜,您可能能够将所需的所有内容存储在内存中。您还需要问自己,您的缓存是否需要分布在多个主机上(无论是现在还是将来)。
考虑到ES中的查找和查询非常快(+ ES为您带来许多其他好处,例如评分),通常比从数据库检索相同的数据更快,因此使用ES作为缓存是有道理的。我看到的一个问题是常见的,即一旦开始复制数据(DB-> ES),就需要确保两个存储库不会失去同步。
现在,如果你将缓存加入其中,那么就需要维护第三个数据存储,并确保它与主数据存储一致。如果你知道你的数据相当稳定,即写入后不经常更新,那么这可能是可以接受的,但你需要时刻牢记这个问题,以便在设计数据访问策略时考虑到这一点。
正如@paweloque所说,最终一切都取决于你的确切用例。每个问题都不同,我可以证明,在过去五年左右的ES项目中,我从未看到过两个配置方式相同的项目。对于某些特定情况,缓存可能是有意义的,但对于其他情况则完全不然。
你需要认真思考如何以及在哪里存储数据,谁在请求它们(以及速率),谁正在创建/更新它们(以及速率),但最佳实践是尽可能保持你的堆栈精简,只使用尽可能少的组件,每个组件都是潜在的瓶颈,你必须理解、集成、维护、调优和监控。
最后,我想再补充一件事情:添加缓存或索引应该被认为是您软件堆栈的性能优化。正如您可能知道的常见说法"过早优化是万恶之源", 您应该首先只使用数据库,测量性能,进行负载测试,然后观察它可能无法支持负载。然后,您才可以决定是否需要加入缓存和/或索引,具体取决于需求。同样,进行负载测试,测量,然后再决定。如果您只有十个用户每天进行少量请求,则仅使用DB可能完全没有问题。您必须了解何时以及为什么需要在您的巴别塔上添加另一层,但更重要的是,您需要逐层添加并查看该层如何改善/降低堆栈的稳定性。

最后但并非不重要的是,你可以找到一些在线文章,这些文章来自使用ES作为缓存(主要是键值存储对象缓存)的人们。


嗨Val,我也在思考同样的问题。我的用例是自动完成,就像谷歌搜索一样,每当一个人输入时,它会查询ES以获取结果。您认为在其中间添加Redis缓存层是否有益? - user1955934
@user1955934并不是因为完成建议器被优化为速度,而且完成数据存储在内存中的FST(有限状态转换器)中。一篇旧文章解释了完成数据与索引在倒排索引中的数据不同。还请阅读此文:https://dev59.com/WVUK5IYBdhLWcg3w7DgH#51085473 - Val
添加redis缓存层可以为ES节省工作量,这样做是否值得呢?如果需要扩展,我们只需扩展ES吗? - user1955934
@user1955934 请再次阅读我的帖子:“过早的优化是万恶之源”。如果您不知道如何进行优化以及为什么要进行优化,那么首先应该尝试不进行优化,然后在必要时再进行优化,因为优化一些您不知道如何优化和为什么要优化的东西是没有意义的。 - Val

9

你的问题:

Q. 缓存解决方案和索引解决方案之间的真正区别是什么?

答:简单的区别在于缓存用于存储频繁使用的数据,以便更快地响应相同的请求。实际上,您的缓存比主存储器更快,但尺寸较小,因此可以存储的数据较少(考虑到通常情况下它会更昂贵)。

索引是对所有数据进行的,以使其更快地可搜索。简单的Hashtable / HashMap具有哈希作为索引,在数组中,0和1是索引。

您可以索引一些列以更快地搜索它们。但是,缓存是您想要拥有数据以更快地获取它们的地方。 通常,缓存是RAM,数据库来自HardDisk

缓存通常也是一个键值存储,因此如果您知道键,则从缓存中获取它,无需运行查询。 在NHibernate和EntityFrameworks中,查询缓存与查询一起插入,作为键的所有数据都被缓存。现在,您的查询将从缓存中获取,而不是通过数据库运行它。


1
所有被频繁搜索的数据或数据都将被添加到索引中吗? - Chang Zhao

2

有趣的问题!你确实可以使用elasticsearch来实现缓存。它提供了一些功能,可以使文档过期,但我不确定它们是否适合用于过期缓存。问题在于elasticsearch并不是为缓存解决方案而构建的。它的优势在于索引和查找文档。

索引是构建索引的任务,就像为书籍做的那样:你阅读整个文本,并写下单词在哪一页上找到。这样我们以后就可以非常快速地找到单词在文本中的位置。

Elasticsearch提供了一个工具箱,允许您定义如何索引和处理文本,例如应用分词。然后,在下一步中,它将为您提供不同类型的查询来查找您的文档。

但是,您可以将文档写入elasticsearch,并使用文档的ID来读取它。这样,您可以将elasticsearch用作存储器,也可以用作缓存。


谢谢。我确实理解索引的作用是用于搜索;唯一不清楚的是它是否使缓存变得多余。通常会怎么做呢?我能想到三种可能性:
  1. 数据库 -> 缓存 -> 搜索索引
  2. 数据库 -> 搜索索引 -> 缓存
  3. 数据库 -> 搜索索引(忽略任何其他缓存)
因此,我真的在努力决定是否需要缓存,如果需要,是搜索索引查询缓存还是缓存查询搜索索引?
- Matt
如果两者同时使用,当然对于复杂的查询,我们会直接去搜索引擎。但是在通过ID检索时,我不确定我们应该先访问缓存(这将查询索引)还是查询索引(这将查询缓存)。 - Matt
我突然想到一个问题:搜索引擎是不是只用于复杂查询(全文搜索),而传统的缓存则用于根据ID返回对象? - Matt
您可以将Elastic作为数据库缓存使用。将数据存储在Elasticsearch中,例如用于结果的表格显示。如果需要更多细节视图的数据,则可以从数据库获取。这非常取决于您确切的用例。 - paweloque

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接