我们有一个现有的 API,其中包含一个使用 Redis 的非常简单的缓存命中/缓存未命中系统。支持Key搜索。因此,转换为以下内容的查询很容易根据其主键进行缓存。
SELECT * FROM [Entities] WHERE PrimaryKeyCol = @p1
任何后续请求都可以通过主键在 REDIS 中查找实体或故障回复到数据库,然后用该结果填充缓存。
我们正在构建一个新的 API,它将允许通过更多参数进行搜索,将在结果中返回多个条目,并且将处于相当高的请求量下(足以影响我们现有的 DTU SQL Azure 中的利用率)。
查询将可以通过其他几个术语进行搜索,一次搜索中的多个 PK,各种其他 FK 查找列,文本上的 LIKE/CONTAINS 语句等...
在这种情况下,有没有我们可以考虑的设计模式或缓存策略。 Redis 似乎不太适合这些类型的查询。我正在考虑简单地散列查询参数,然后将该散列缓存为键,并将整个结果集缓存为值。
但考虑到 Redis 的键值性质,以及一个实体可能包含在多个查询哈希下的多个结果集中这一事实,这感觉有点天真。
(作为引用,此数据的来源目前是 SQL Azure,我们正在使用 Azure 的托管 Redis 服务。我们还在寻找访问数据库的替代方法,包括对数据进行非规范化、对数据进行 ETL 处理到 CosmosDB,在 Azure 搜索中托管数据,但这样做还有其他影响,包括实现时间、数据的“新鲜度”等...)
最佳答案
就我个人而言,我不会尝试缓存结果,只会缓存单个实体。当我过去做过这样的事情时,我会从实时查询中返回一个 ID 列表,并从我的缓存层中检索单个实体。这样 ID 列表始终是“新鲜的”,并且您不会遇到讨厌的缓存失效逻辑问题。
如果您确实有经常重复出现的搜索,您可以缓存(id 的)结果,但您可能会遇到分页等问题。缓存查询结果可能很棘手,因为您通常需要缓存所有 结果,而不仅仅是第一个“页面”值。这通常非常昂贵,并且具有超过缓存值(value)的高传输成本。
此外,您绝对会遇到缓存查询结果的新鲜度问题。当新记录出现时,它们不会出现在缓存列表中。使用仅实体缓存可以避免这种情况,因为 ID 列表始终是新鲜的,只有实体本身可能是陈旧的(但它有一种更简单的缓存过期方法)。
如果您担心实体过时,您不仅可以返回一个 ID,还可以返回一个“最后更新日期”,这样您就可以比较每个实体与缓存的新鲜度。
关于复杂查询的缓存策略/设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49009127/