复杂查询的缓存策略/设计模式

时间:2018-02-27 12:49:15

标签: caching design-patterns redis architecture azure-sql-database

我们有一个现有的API,它使用Redis非常简单的缓存命中/缓存未命中系统。它支持按键搜索。因此,根据它的主键,可以轻松缓存转换为以下内容的查询。

SELECT * FROM [Entities] WHERE PrimaryKeyCol = @p1

任何后续请求都可以通过它的主键在REDIS中查找实体,或者故障回复到数据库,然后使用该结果填充缓存。

我们正在构建一个允许搜索更多参数的新API,会在结果中返回多个条目,并且会在相当高的请求量下(足以影响我们的SQL Azure中现有的DTU利用率)。

查询将可以通过其他几个术语进行搜索,一次搜索中有多个PK,各种其他FK查找列,文本上的LIKE / CONTAINS语句等等......

在这种情况下,我们可以考虑任何设计模式或缓存策略。 Redis似乎并不适合这些类型的查询。我考虑简单地散列查询参数,然后将该散列缓存为键,将整个结果集作为值。

但考虑到Redis的键值特性以及一个实体可能包含在多个查询哈希下的多个结果集中,这感觉就像是一种天真的方法。

(作为参考,此数据的来源目前是SQL Azure,我们正在使用Azure的托管Redis服务。我们还在寻找其他方法来访问数据库,包括。对数据进行非规范化,将数据ETL到CosmosDB,在Azure Search中托管数据,但这样做还有其他影响,包括实现时间,数据的新鲜度等等......)

1 个答案:

答案 0 :(得分:3)

就个人而言,我不会尝试缓存结果,只是单个实体。当我以前做过这样的事情时,我会从实时查询中返回一个ID列表,并从我的缓存层中检索单个实体。这样,ID列表总是"新鲜",并且您不会有令人讨厌的缓存失效逻辑问题。

如果你确实经常进行重复搜索,你可以缓存(ids)的结果,但是你可能会遇到分页等问题。缓存查询结果可能很棘手,因为您通常需要缓存所有结果,而不仅仅是第一个"页面"价值。这通常非常昂贵,并且具有超过缓存值的高传输成本。

此外,缓存查询结果绝对会出现新鲜度问题。随着新记录的出现,他们不会进入缓存列表。使用仅实体缓存可以避免这种情况,因为ID列表总是新鲜的,只是实体本身可能是陈旧的(但是它具有更容易的缓存到期方法)。

如果您担心实体的陈旧性,您不仅可以返回ID,还可以返回"上次更新日期",它允许您将每个实体的新鲜度与缓存进行比较。