使用Cassandra作为事件存储

时间:2013-10-11 15:20:19

标签: cassandra

我想尝试在事件采购应用程序中使用Cassandra作为事件存储。我对事件存储的要求非常简单。事件“架构”将是这样的:

  • id :聚合根实体的ID
  • 数据:序列化事件数据(例如JSON)
  • 时间戳:事件发生时
  • sequence_number :事件的唯一版本

我对卡珊德拉来说是全新的,所以请原谅我对我即将写的东西的无知。我只想在这些数据上运行两个查询。

  1. 为我提供给定聚合根ID的所有事件
  2. 如果序列号为>,请给出给定聚合根的所有事件。 X
  3. 我的想法是在CQL中创建一个Cassandra表,如下所示:

    CREATE TABLE events (
      id uuid,
      seq_num int,
      data text,
      timestamp timestamp,
      PRIMARY KEY  (id, seq_num) );
    

    这似乎是一种模拟问题的明智方法吗?而且,重要的是,使用复合主键是否允许我有效地执行我指定的查询?请记住,在给定用例的情况下,对于相同的聚合根id,可能会有大量事件(具有不同的seq_num)。

    我特别关注的是第二个查询在某种程度上效率低下(我在这里考虑二级索引......)

6 个答案:

答案 0 :(得分:6)

您的设计似乎很好地用“cassandra术语”建模。 “复合键”表确实支持您需要的查询,您可以使用以下内容:

  • 查询1:select * from events where id = 'id_event';
  • 查询2:select * from events where id = 'id_event' and seq_num > NUMBER;

我认为第二个查询效率不高,但它可能会返回很多元素......如果是这种情况,您可以设置要返回的事件的“限制”。如果可以,您可以使用limit关键字。

使用复合键似乎非常适合您的特定要求。使用“二级索引”似乎没有带来太大的影响......除非我错过了你的设计/要求。

HTH。

答案 1 :(得分:2)

您所获得的是好的,除非特定聚合的许多事件发生。你可以做的一件事是创建一个静态列来保持" next"和" max_sequence"。这个想法是静态列将保存此分区的当前最大序列,以及"仿真id"为下一个分区。然后,您可以为每个分区存储100或1000个事件。您基本上已经完成的工作是将聚合事件分成多个分区。这将意味着查询和存储的额外开销,但同时防止无限增长。您甚至可以为聚合创建分区查找。真的取决于你的用例以及如何"聪明"你希望它成为。

答案 2 :(得分:2)

我一直在使用Cassandra进行非常类似的场景(每行100k +列),并以接近你的模型结束。我也同意emgsilva认为二级指数可能不会带来太多。

有三件事对我们的事件存储的良好性能有重要意义:使用复合列,确保列的排序顺序很好(Cassandra按行按行排序),并使用紧凑的存储如果可能的话。

请注意,紧凑型存储意味着您只能拥有一个值列。因此,您需要将所有其他列作为密钥的一部分。

对你而言,架构将是:

CREATE TABLE events (
    id uuid,
    seq_num int,
    timestamp timestamp,
    data text,
    PRIMARY KEY  (id, seq_num, timestamp))
    WITH COMPACT STORAGE;

答案 3 :(得分:0)

您的分区键太精细,您应该创建复合分区键或更改它以获得更好的时间序列建模性能。例如

CREATE TABLE events (
    event_date int,
    id timeuuid,
    seq_num int,
    data text,
    PRIMARY KEY  (event_date, id) );

这样,您的ID将成为一个聚类列,只是为了保证事件的单一性,您的分区键(即20160922)可以每天对所有事件进行分组。您也可以将其更改为月份。避免使用uuid使用timeuuid,它已经存储了时间戳信息。

答案 4 :(得分:0)

该设计似乎与Cassandra如何存储数据(主键的第一部分)保持一致,即您的“ id”将用于在单独的节点/ v节点上划分数据(取决于集群的方式)配置),对于Cassandra来说,这将使您为第一个查询获取数据非常容易,因为它仅需触摸单个分区,现在根据键的第二部分将是一个聚簇键,即将指定数据的方式在该分区内排序,这是您的第二个查询的全部内容。请记住,只要所有数据的设计方式都使得表上的每个查询仅涉及单个分区,那么您就可以开始使用。同样,如果您担心第二个查询将返回大量数据,则始终可以选择Cassandra固有地为范围查询提供的分页。

答案 5 :(得分:-4)

我不赞成你的设计在eventstore上保存aggregateroot.you可以保存domainevent的灵活性。 我解释eventdomain是最细粒度的数据,使得应用程序状态的变化.aggregateroot不与eventstore不匹配,它用于数据交换或boundedcontext。 当您使用域事件时,您可以使用plolygot建模重建您的数据甚至aggregateateroot。您可以管理模型以满足您的客户和约束的需要。所以您为domainobject之间的链接建模图形,之后使用neo4j,此外您还建模聚合模型和你使用documentdatabase。我的意思是你有机会改变模型并使用方便的持久性引擎。这是polygot数据和polygot持久性之间的区别。 在你的策略中,我理解两种方式: 如果您需要在domainevent和cassandra数据库上建模的事件。 如果您需要聚合数据或模型而没有事件源,则使用文档化数据库,您可以检索这两个查询。

你可以消除对域驱动设计的困惑。