【问题标题】:Sliding Window TTL in CassandraCassandra中的滑动窗口TTL
【发布时间】:2017-08-01 05:11:19
【问题描述】:

我正在研究 Cassandra 以寻找一个潜在的即将到来的项目,我认为它可能非常适合。困扰我的一个潜在地方是数据保留的要求。基本上我们有这样的架构:

CREATE TABLE Things (
  user_id int
  thing_id int
  a text static
  b text static
  .... more static fields
  updated_at timestamp static


  type text
  subthing_id int

  PRIMARY KEY (user_id, thing_id, subthing_id)
)

在关系数据库术语中,我会说一个事物属于一个用户,而一个事物有许多子事物。

Thing 具有与其相关联的各种子事物,这些子事物稍后会执行新的插入操作,进而更新相应的静态字段。在最后一次为该事物插入子事物后,我们需要将每个事物存储 30 天。例如,事物 A 和事物 B 被插入。一周后插入事物 B 的子事物。事物 A 在初次插入后 30 天被删除。事物 B(以及所有相关的子事物)在 7 天后被删除。

据我所知,我不能只插入 TTL,因为我需要更新共享相同 user_id 和 thing_id 的其他事物行的 TTL。我也不完全确定如何在这里运行 DELETE 命令,因为我没有通过任何键删除。我相信这里的主键是正确的,因为所有查询都将基于 user_id(除了由 updated_at 确定的删除)。

我的另一个担忧是墓碑的想法。我只读过它们,但这里担心的是我每天可能会删除数百万个这些东西。执行每日删除后是否需要每日压缩?

更新: 自从原始发布以来,我想到了一个替代方案,即每次添加子项时都会插入第二个表。它看起来像:

CREATE TABLE  Expirations (
  expiry date
  user_id int
  thing_id int
  PRIMARY KEY (expiry, user_id, thing_id)
)

其中 expiry 是要删除的给定 user_id 和 thing_id 的日期。当事物被插入到事物表中时,必须根据需要更新该表,然后我必须每天运行一些东西来查询今天到期的值并遍历它们以从事物表中删除事物。我不确定这是否被认为是“Cassandra 方式”,但它似乎可以工作。

【问题讨论】:

    标签: cassandra cql3


    【解决方案1】:

    这是一个有趣的挑战。我会使用map data type 将每个thing_id 映射到它的所有subthing_ids。我会选择类似的东西:

    CREATE TABLE Things (
      partition_date timestamp,
      insertion_date timestamp,
      user_id int,
      thing_map map<int,int>
      a text static
      b text static
      .... more static fields
      updated_at timestamp static
    
    
      type text
    
      PRIMARY KEY (partition_date, insertion_date, user_id)
    ) WITH CLUSTERING ORDER BY (insertion_date DESC)
    

    在这里,我插入了一个新字段 insertion_date,它应该准确地保存插入日期,以及一个新字段 partition_date,它成为新的唯一 PARTITION KEY,它应该存储 insertion_date 字段的截断,以避免一些热点(由于您的 TTL 要求,我假设可以简单地基于一天字段进行查询,如果您需要查询 user_id 字段,情况会有所不同)。我最近回答了有关此建模问题herehere 的类似问题,因此请查看这些以获取有关所使用技术的更多信息(称为bucketing)。

    然后是thing_map,这是您问题的核心。在地图中推送一个新对象应该完全重置该地图的 TTL,这样就可以为您提供完全所需的行为。请注意,TTL 将仅删除 字段,而不是整行,您只需测试它是否为空。

    最后,墓碑行为是您将不得不面对的问题。如果您负担得起完整的行重写,那么您将立即更新所有行,而不是仅更新 map 字段,您将在分区级别获得删除,以及我用“反向时间序列”建模的集群键应该可以解决这个问题而不会出现太多问题。

    【讨论】:

    • 感谢您的回复!不过我有几个问题。因此,如果每个查询都基于用户 ID,我很确定 user_id 必须是分区键。日期可以作为这些查询的一部分包含在内,但它是可选的。唯一一次使用日期并且不使用 user_id 是在查询中删除过期的东西。我想归根结底是让 DELETE 命令或 SELECT 查询命中尽可能少的分区更好。我正在用我认为可能也可行的替代方法更新原始问题...让我知道您对此的想法。
    • @ShaneAndrade:您始终可以将dateuser_id 放在一起,以更好地分区您的数据。如前所述,您可以在我发布的链接中找到如何执行此操作。另请注意,如果您使用TTL,那么数据将自动消失,因此您根本不需要执行任何SELECT/DELETE。拥有两张桌子是另一种可行的选择,但你有TTL...
    猜你喜欢
    • 1970-01-01
    • 2016-03-06
    • 2013-04-03
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 2017-06-08
    • 2012-03-05
    • 2012-08-08
    相关资源
    最近更新 更多