首页 > 解决方案 > 构造唯一性由 6 个属性定义的缓存键的最佳方法

问题描述

目前,我的任务是为类似电子商务的系统修复缓存,该系统的价格取决于许多因素。缓存后端是redis。对于给定的产品,影响价格的因素是:

库存单位

渠道

子频道

计划

日期

目前,redis 中的缓存结构如下:

product1_channel1_subchannel1:  {sku_1:  {plan1: {2019-03-18: 2000}}}

API 可满足对多种产品、sku 和上述所有因素的请求。因此他们决定在 product_channel_subchannel 级别上查询所有数据并过滤应用程序中的数据,这非常慢。他们还决定,在缓存未命中时,他们将为所有 skus 构建 90 天数据的缓存。这样,只有一个请求会面临愤怒,而其他请求会从中受益(唯一的问题是我们现在更频繁地破坏缓存,这也拖累了系统)

将所有这些因素都包含在键中的缺点是键太多。球场有 400 种产品,每个产品由 20 个 sku 组成,20 个渠道,200 个子渠道 3 种计划和 400 天的定价。为了避免在某个地方出现这么多键,我们必须对数据进行分组。

系统当前接收大约 10 rps 并且必须在 100ms 内响应。

问题是:

上面的缓存结构好吗?或者我们如何去扁平化这个结构?

缓存通常如何存储在定价系统中。我觉得这是一项非常微不足道的任务,但我发现很难证明我的方法是正确的

是否可以牺牲一个请求来为大量数据预热缓存?还是有缓存预热策略更好?

标签: cachingredis

解决方案


任何类型的缓存策略都需要权衡取舍。您需要做出的精确权衡取决于复杂的领域逻辑,除非您尝试过,否则您无法预测。

这意味着无论您实施什么都应该基于数据,并且应该足够灵活,可以随着业务的变化而随时间而变化。特别是这些问题的答案:

是否可以牺牲一个请求来为大量数据预热缓存?还是有缓存预热策略更好?

取决于用户如何查询数据以及缓存未命中需要多长时间。如果查询倾向于以可预测的方式围绕某些 sku 或某些日期聚集,那么您应该使用该信息来帮助指导缓存命中和未命中。

如果不进行适当的实验,我或其他任何人都无法给你一个正确的答案,但我们可以给你一些指导。

以下是我在使用 redis 进行缓存时推荐的一些最佳实践:

  1. 如果瓶颈是从 redis 向 api 发送数据,那么可以考虑使用 lua 脚本在任何数据离开 redis 之前进行简单的处理。但是,请注意不要让脚本过于复杂,因为长时间运行的 lua 脚本会阻塞 redis 的所有其他部分
  2. 看起来您正在使用简单的 get/set 键来存储数据。考虑使用更复杂的东西:

    一个。如果您希望按日期更好地访问数据(使用日期作为分数),请使用排序集 (zsets)。湾。使用哈希集获得对 sku 的更细粒度的访问

  3. 根据您的问题,您似乎将拥有大约 160 万个密钥。这不是一个很大的数量,但是您需要确保 redis 有足够的内存来将所有内容存储在 ram 中,而无需将任何内容交换到磁盘。这是我们必须努力学习的东西。如果您在 linux 上运行您的 redis 实例,则必须将系统的 swappiness 设置为 0,以确保从不使用 swap。

但是,最重要的是,您需要尝试一切,直到找到一个好的解决方案。


推荐阅读