caching - 构造唯一性由 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 内响应。
问题是:
上面的缓存结构好吗?或者我们如何去扁平化这个结构?
缓存通常如何存储在定价系统中。我觉得这是一项非常微不足道的任务,但我发现很难证明我的方法是正确的
是否可以牺牲一个请求来为大量数据预热缓存?还是有缓存预热策略更好?
解决方案
任何类型的缓存策略都需要权衡取舍。您需要做出的精确权衡取决于复杂的领域逻辑,除非您尝试过,否则您无法预测。
这意味着无论您实施什么都应该基于数据,并且应该足够灵活,可以随着业务的变化而随时间而变化。特别是这些问题的答案:
是否可以牺牲一个请求来为大量数据预热缓存?还是有缓存预热策略更好?
取决于用户如何查询数据以及缓存未命中需要多长时间。如果查询倾向于以可预测的方式围绕某些 sku 或某些日期聚集,那么您应该使用该信息来帮助指导缓存命中和未命中。
如果不进行适当的实验,我或其他任何人都无法给你一个正确的答案,但我们可以给你一些指导。
以下是我在使用 redis 进行缓存时推荐的一些最佳实践:
- 如果瓶颈是从 redis 向 api 发送数据,那么可以考虑使用 lua 脚本在任何数据离开 redis 之前进行简单的处理。但是,请注意不要让脚本过于复杂,因为长时间运行的 lua 脚本会阻塞 redis 的所有其他部分
看起来您正在使用简单的 get/set 键来存储数据。考虑使用更复杂的东西:
一个。如果您希望按日期更好地访问数据(使用日期作为分数),请使用排序集 (zsets)。湾。使用哈希集获得对 sku 的更细粒度的访问
根据您的问题,您似乎将拥有大约 160 万个密钥。这不是一个很大的数量,但是您需要确保 redis 有足够的内存来将所有内容存储在 ram 中,而无需将任何内容交换到磁盘。这是我们必须努力学习的东西。如果您在 linux 上运行您的 redis 实例,则必须将系统的 swappiness 设置为 0,以确保从不使用 swap。
但是,最重要的是,您需要尝试一切,直到找到一个好的解决方案。
推荐阅读
- php - 500 服务器错误 laravel 最新版本 php
- mysql - MySQL:为什么每个组查询的最大 N 个成员有效?
- php - Wordpress:WP_Query 中每种帖子类型的不同选项
- rider - 在 Rider 中将设置应用为机器范围
- excel - 如何在不同的工作表中复制形状?
- pandas - 如何根据熊猫中的if-else条件从元组索引中提取字符串?
- c++ - 如何在 C++ 中为 cin.ignore() 指定多个分隔符?
- javascript - Reactjs实时禁用按钮onclick
- azure - 如何将私有链接用于 Synapse 工作区 SQL On-Demand?
- python - 如何解决 ValueError:无法找到令牌种子!https://translate.google.com 有变化吗?