Redis 建议 - 何时对数据进行分组以及何时将其拆分

Posted

技术标签:

【中文标题】Redis 建议 - 何时对数据进行分组以及何时将其拆分【英文标题】:Redis advice- when to group data and when to split it up 【发布时间】:2022-01-05 17:51:36 【问题描述】:

希望从那些一直在战壕中的人那里得到一些明智的建议,并且可以帮助我更好地了解何时将数据聚集在 Redis 中,以及何时将其拆分。

我正在开发一个多租户平台,该平台每 3-5 秒为我跟踪的每项资产提供 GPS 数据。在处理数据时,我们会存储与资产相关的其他信息(即是否准时、是否迟到等)。

每项资产都属于一个或多个租户。例如,当跟踪一辆家用汽车时,该汽车可能为丈夫和妻子而存在。每个人都需要知道它与他们的需求相关的位置。例如,这辆车可能正在被青少年使用,并且丈夫在下午 3:00 准时使用它,但妻子在下午 2:30 使用它却迟到了。

作为一项附加要求,单个租户可能需要对其他租户的读取权限。 IE。爸爸想看看家里的车,以及任何青少年的车。所以层次结构可以开始看起来像这样:

超级租户--

--Super Tenant (Family)
   --Tenant (Dad)
      --Vehicle 1
         --Gps:123.456,15.123
         --Status:OnTime
      --Vehicle 2
         --Gps:123.872,15.563
         --Status:Unused
   --Tenant (Mom)
      --Vehicle 1
         --Gps:123.456,15.123
         --Status:Late
      --Vehicle 2
         --Gps:123.872,15.563
         --Status:Unused
   --Tenant (Teenager)
      --Vehicle 1
         --Gps:123.456,15.123
         --Status:Unused
      --Vehicle 2
         --Gps:123.872,15.563
         --Status:Unused

我的问题与将其存储在 Redis 中的最佳方式有关。

我可以按租户存储 - I.E.我可以为爸爸使用钥匙,然后收集他可以使用的所有车辆。每次出现新的 GPS 位置时(无论是车辆 1 还是车辆 2),我都会更新集合的内容。我担心的是,如果有几十辆汽车,我们会经常更新他的收藏方式。

或者

我可以按租户存储,然后按车辆存储。这意味着当车辆 1 的 GSP 位置进入时,我将更新 3 个不同租户的信息。还不错。

让我停下来的是,我正在开发一个网站,让爸爸可以看到他所有的车辆。那个电话会打进来,询问爸爸租户名下的所有车辆。如果我拆分数据以便按租户/车辆存储,那么我将不得不存储爸爸有 2 辆车的事实,然后向 Redis 询问(key1、key2 等)中的所有内容。

如果我将所有内容都存储在 Dad 租户下的集合中,那么我对 Redis 的请求会简单得多,并且会请求密钥 Dad 下的所有内容。

实际上,每个租户将拥有 5-100 辆汽车,而我们有 100 多个租户。

根据您的经验,您的首选方法是什么(请随意提供此处未提供的方法)。

【问题讨论】:

【参考方案1】:

从您的问题看来,您希望将所需的所有内容存储在一个密钥下。 Redis 不按原样支持嵌套哈希。这个answer 提供了一些关于如何解决的建议。

根据 GPS 数据的更新节奏,最好将所需的写入总数降至最低。这可能会增加在读取时构建响应的操作数;但是,添加只读从属实例应该允许您扩展读取。您可以通过一些更新流水线来调整您的写入。

根据您的描述,听起来更新仅限于用户的 GPS 和车辆状态。读取时请求的数据将用于单个用户查看他们的车辆位置和状态集。

我将从一个租户开始,该租户存储为带有用户名的哈希,以及一个引用与用户关联的车辆和会话的字段。如果您采用类似的命名约定,这实际上不是必需的,但如果需要缓存其他用户数据,则显示为一个选项。

- Tenant user-1 (Hash)
-- name: Dad (String)
-- vehicles: user-1:vehicles (String) reference to key for set of vehicles assigned.
-- sessions: user-1:sessions (String) reference to key for set of user-vehicle sessions.

如果不需要其他租户数据,则可以使用密钥格式查找车辆。成员将是对车辆钥匙的引用。

- UserVechicles user-1:vehicles (Set)
-- member: vehicle-1 (String)

这将允许查找车辆的详细信息。车辆将有自己的位置。您可以包含一个字段来引用类似于以下用户会话的以车辆为中心的会话时间表。如果还需要响应,您也可以放置车辆名称或其他数据。

- Vehicle: vehicle-1 (Hash) 
-- gps: "123.456,15.123" (String)

将特定于用户的会话存储在排序集中。成员将是对存储会话信息的密钥的引用。分数将设置为时间戳值,允许对该用户最近和即将到来的会话进行范围查找。

- Schedule user-1:sessions
-- member: user-1:vehicle-1:session-1 (String)
-- score: 1638216000 (Float)

车辆上的租户会话,您只需在字符串中列出状态即可。如果您需要支持以车辆为中心的时间表视图,此处显示了一个替代方案,该替代方案将允许存储计划和可用时间的附加状态。将此与一组排序的车辆会话相结合将完善这一点。

- Session user-1:vehicle-1:session-1 (Hash)
-- status: OnTime (String)
-- scheduled_start: 1638216000 (String) [optional]
-- scheduled_end: 1638216600 (String) [optional]
-- earliest_available: 1638215000 (String) [optional]

如果您没有在其他地方跟踪状态,您可以使用哈希来存储您拥有的缓存对象的计数器,以便在发布新对象时使用。添加新缓存对象时读取并增加这些值。

- Globals: global (Hash)
-- user: 0
-- vehicle: 0
-- session: 0

对于更新,您将拥有:每个更新周期 20 万次写入操作。 100k 租户-车辆(1000 个租户 * 100 个车辆/租户)每辆带有

1 辆 HSET 车辆 1 个 HSET 会话

流水线和调整流水线中的请求数量可以提高写入性能,但我预计您应该能够在

对于读取,您会得到类似:每个用户每个请求约 300 次操作。

1 个 HGETALL 用户 1 ZRANGESTORE tempUSessions user-sessions LIMIT 200(在一个时间范围内为用户查找最多 200 个会话) 200 个 HGETALL 会话 1 SMEMBERS 用户车辆(查找用户的所有车辆) 100 HGET 车辆 gps(获取所有车辆的车辆位置)

注意事项:

在会话通过后定期删除会话及其引用的过程将防止内存无限增长并保持性能一致。

添加一些脚本,以便在添加新用户或车辆时更轻松地更新缓存,并返回您描述的需要显示给用户的状态,这样可以解决这个问题。

【讨论】:

非常感谢! 乐于助人。这是一个有趣的问题。

以上是关于Redis 建议 - 何时对数据进行分组以及何时将其拆分的主要内容,如果未能解决你的问题,请参考以下文章

如何以及何时为 graphql 生成 ID?

在 GraphQL 服务器设置中何时使用 Redis 以及何时使用 DataLoader

索引的优缺点,何时用或不用索引

何时使用SESSION以及何时在Web应用程序中使用GET进行参数传递?

何时以及如何为离散卷积进行零填充?

何时使用 Redis?啥时候去塔兰图尔?