Cassandra 卡桑德拉:轮换名单

Cassandra 卡桑德拉:轮换名单,cassandra,Cassandra,假设我将事件列表存储在Cassandra行中,并使用复合列实现: { event:123 => 'something happened' event:234 => 'something else happened' } 就我所知,这是一种常见的模式。与使用jsonized列表的单个列event相比,它的伸缩性更好,因为在列表中添加一个新项很容易,无需先读取它,然后再写回去 但是,现在我需要实现这两个要求: 如果上次添加的事件相同,我不想添加新事件 我只想保留最后的

假设我将事件列表存储在Cassandra行中,并使用复合列实现:

{
    event:123 => 'something happened'
    event:234 => 'something else happened'
}
就我所知,这是一种常见的模式。与使用jsonized列表的单个列
event
相比,它的伸缩性更好,因为在列表中添加一个新项很容易,无需先读取它,然后再写回去

但是,现在我需要实现这两个要求:

  • 如果上次添加的事件相同,我不想添加新事件
  • 我只想保留最后的N个事件

有没有标准的方法可以做到最好的性能?(任何存储架构更改都可以)。

检查事物是否已经存在,或者检查存在多少并删除额外的项,都是读-修改-写操作,它们不太符合Cassandra的约束条件

仅保留N last事件的一种方法是确保它们已排序,以便您可以执行范围查询并读取N last(例如,在列键前面加上时间戳/TimeUUID)。这不会删除过时的事件,您需要将其作为一个单独的进程来执行,但通过这种方式,查询数据的代码将只看到最后的N个事件,如果我正确解释了这些事件,这才是真正的要求。旧事件的垃圾收集只是一种优化,以避免保留不再需要的东西

如果要求不是严格的N个事件,但是事件的时间不超过t,那么当然可以使用TTL特性,但我认为这不是您的选项

第一个要求更为棘手。你可以在写之前先读,然后检查你是否有一个项目,但这会很慢,除非你在Cassandra之外进行某种锁定,否则不能保证两个编写器不会同时读然后都写,这样两个编写器都看不到对方的写。也许这对你来说不是问题,但是没有好办法。卡桑德拉不做CAS


在使用Cassandra时,我处理类似情况的方法是在应用程序节点中保留已写入内容的缓存,并在写入之前进行检查。然后,您需要确保每个应用程序节点都能看到同一行的所有事件,并且同一行的事件不会分布在多个应用程序节点上。一种方法是在应用程序节点前面有一个消息队列系统,并使用与数据库中的行键相同的键将事件流划分到多个队列上。

这不是一个真正的答案,但第一点是,是否有一些唯一的标识符可以用作键的一部分,让相同的事件得到相同的密钥?这将为您节省一个读->写周期。对于第二点,它必须是最后的N,还是可以是指定时间窗口内的N?如果时间窗口起作用,您可以对行应用TTL,使它们在一段时间后消失。@很遗憾,这将不允许跟踪像“a->B->a->B”这样的事件序列(它们看起来像“a->B”)。对于TTL,我需要确保至少有N个最后的事件被无限长地保留。实际上,现在看来我对需求的定义有点太低了。我真正需要的是保留一个事件序列,但为了保持空间,我们只需要保留最后N个,但遗憾的是,TTL不是一个选项。此外,报告事件的外部系统可能会使用不同的时间戳多次重新发送同一事件,我们不想为这些重复事件浪费空间。那么您如何识别“重复事件”?纯粹是字符串消息吗?@MyseriousDan是的,只是字符串消息。现在,我们决定继续使用原始的
[event;timestamp]=>value
方法,如果需要,通过一些批处理作业清理旧垃圾,并在应用程序中缓存事件。