Cassandra 数据建模 - 我是否选择热点以使查询更容易?
Cassandra data modeling - Do I choose hotspots to make the query easier?
是否可以构建一个数据模型,使提取查询更容易,即使它可能会在集群内创建热点?
阅读时请记住,我现在没有使用 Solr,考虑到访问这些数据的频率,我认为使用 spark-sql 不合适。我想保留它作为纯 Cassandra。
我们有事务,它们使用 UUID 作为分区键建模,以便数据在集群中均匀分布。我们的一种访问模式要求 UI 获取给定用户和日期范围的所有记录,查询如下:
select * from transactions_by_user_and_day where user_id = ? and created_date_time > ?;
我构建的第一个模型使用 user_id 和 created_date(创建事务的日期,始终设置为午夜)作为主键:
CREATE transactions_by_user_and_day (
user_ id int,
created_date timestamp,
created_date_time timestamp,
transaction_id uuid,
PRIMARY KEY ((user_id, created_date), created_date_time)
) WITH CLUSTERING ORDER BY (created_date_time DESC);
这个table似乎表现不错。使用 created_date 作为 PK 的一部分允许用户更均匀地分布在集群周围以防止热点。然而,从访问的角度来看,它使数据访问层做了我们希望做的更多工作。它最终不得不在提供的范围内创建一个包含所有日期的 IN 语句,而不是给出一个日期并且大于运算符:
select * from transactions_by_user_and_day where user_id = ? and created_date in (?, ?, …) and created_date_time > ?;
为了简化在数据访问层完成的工作,我考虑过像这样对数据建模:
CREATE transactions_by_user_and_day (
user_id int,
created_date_time timestamp,
transaction_id uuid,
PRIMARY KEY ((user_global_id), created_date_time)
) WITH CLUSTERING ORDER BY (created_date_time DESC);
使用上述模型,数据访问层可以为用户获取 transaction_id,并在 Cassandra 中过滤特定日期范围。但是,这会导致集群内出现热点的可能性。长寿 and/or 高流量的用户将在该行中创建更多的列。我们打算为数据提供一个 TTL,这样任何超过 60 天的数据都会被丢弃。此外,我分析了数据的大小,我们最大量用户的 60 天数据价值不到 2 MB。计算一下,如果我们假设所有 40,000 个用户(这个数字不会显着增长)均匀分布在一个 3 节点集群上,每个用户 2 MB 的数据,那么每个节点的最大数据量将超过 26 GB ((13333.33* 2)/1024)。实际上,您不会以 1/3 的用户完成那么多的工作量而告终,而且您不得不非常不幸地让 Cassandra 使用 V-Nodes 将所有这些用户放在一个节点上。从资源的角度来看,我认为 26 GB 也不会成就或破坏任何东西。
感谢您的想法。
日期模型 1:Something 否则您可以更改数据访问层以单独查询每个 ID,而不是使用 IN 子句。查看此页面以了解为什么会更好。
数据模型 2:每个节点 26GB 的数据看起来并不多,但是 2MB 的 fetch 似乎有点大。当然,如果这是异常值,那么我看不出有什么问题。您可以尝试设置一个 cassandra-stress 作业来测试模型。只要您的大部分分区小于 2MB,就可以了。
另一种解决方案是将数据模型 2 与分桶结合使用。这会给您带来更多的写入开销,因为您还必须维护存储桶查找 table。如果需要我详细说明这种方法,请告诉我。
是否可以构建一个数据模型,使提取查询更容易,即使它可能会在集群内创建热点?
阅读时请记住,我现在没有使用 Solr,考虑到访问这些数据的频率,我认为使用 spark-sql 不合适。我想保留它作为纯 Cassandra。
我们有事务,它们使用 UUID 作为分区键建模,以便数据在集群中均匀分布。我们的一种访问模式要求 UI 获取给定用户和日期范围的所有记录,查询如下:
select * from transactions_by_user_and_day where user_id = ? and created_date_time > ?;
我构建的第一个模型使用 user_id 和 created_date(创建事务的日期,始终设置为午夜)作为主键:
CREATE transactions_by_user_and_day (
user_ id int,
created_date timestamp,
created_date_time timestamp,
transaction_id uuid,
PRIMARY KEY ((user_id, created_date), created_date_time)
) WITH CLUSTERING ORDER BY (created_date_time DESC);
这个table似乎表现不错。使用 created_date 作为 PK 的一部分允许用户更均匀地分布在集群周围以防止热点。然而,从访问的角度来看,它使数据访问层做了我们希望做的更多工作。它最终不得不在提供的范围内创建一个包含所有日期的 IN 语句,而不是给出一个日期并且大于运算符:
select * from transactions_by_user_and_day where user_id = ? and created_date in (?, ?, …) and created_date_time > ?;
为了简化在数据访问层完成的工作,我考虑过像这样对数据建模:
CREATE transactions_by_user_and_day (
user_id int,
created_date_time timestamp,
transaction_id uuid,
PRIMARY KEY ((user_global_id), created_date_time)
) WITH CLUSTERING ORDER BY (created_date_time DESC);
使用上述模型,数据访问层可以为用户获取 transaction_id,并在 Cassandra 中过滤特定日期范围。但是,这会导致集群内出现热点的可能性。长寿 and/or 高流量的用户将在该行中创建更多的列。我们打算为数据提供一个 TTL,这样任何超过 60 天的数据都会被丢弃。此外,我分析了数据的大小,我们最大量用户的 60 天数据价值不到 2 MB。计算一下,如果我们假设所有 40,000 个用户(这个数字不会显着增长)均匀分布在一个 3 节点集群上,每个用户 2 MB 的数据,那么每个节点的最大数据量将超过 26 GB ((13333.33* 2)/1024)。实际上,您不会以 1/3 的用户完成那么多的工作量而告终,而且您不得不非常不幸地让 Cassandra 使用 V-Nodes 将所有这些用户放在一个节点上。从资源的角度来看,我认为 26 GB 也不会成就或破坏任何东西。
感谢您的想法。
日期模型 1:Something 否则您可以更改数据访问层以单独查询每个 ID,而不是使用 IN 子句。查看此页面以了解为什么会更好。
数据模型 2:每个节点 26GB 的数据看起来并不多,但是 2MB 的 fetch 似乎有点大。当然,如果这是异常值,那么我看不出有什么问题。您可以尝试设置一个 cassandra-stress 作业来测试模型。只要您的大部分分区小于 2MB,就可以了。
另一种解决方案是将数据模型 2 与分桶结合使用。这会给您带来更多的写入开销,因为您还必须维护存储桶查找 table。如果需要我详细说明这种方法,请告诉我。