在Cassandra

时间:2015-12-24 11:24:49

标签: cassandra cassandra-2.2

我第一次和Cassandra一起玩,我觉得我理解基本和限制。作为一个例子,我正在使用以下模型来存储通过hashtag收集的推文。

create table posts
(
    id text,
    status text,
    service text,
    hashtag text,
    username text,
    caption text,
    image text,
    link text,
    repost boolean,
    created timestamp,
    primary key (hashtag, created)
);

这对我需要的查询类型非常有用:

select * from posts where hashtag = 'demo' order by created desc;

但是,如果我理解正确,我可以使用单一的“演示”分区键存储的帖子数量有一个上限,更重要的是,匹配“演示”分区键的整个帖子集会有与每个副本一起存储。如果我理解正确的话,我应该使用更随机或可变的分区键(可能是帖子的id),但我不知道使用什么不会改变查询的要求。

如果我使用id作为分区键(例如PRIMARY KEY (id, created))并在hashtag列上添加辅助索引,则在运行查询时会出现以下错误:

ORDER BY with 2ndary indexes is not supported.

我得到使用ORDER BY,分区键必须在where子句中显示,因此我原来认为使用hashtag。

我是否过度思考或者是否有更好的分区键候选者?

1 个答案:

答案 0 :(得分:2)

您前进的方向取决于您期望的写入量以及群集的大小。

如果你有一个小型用户社区和一个小型集群,那么你可能会过度思考。理论上,分区最多可容纳20亿行。这是一个很大的数字,并且任何人真的想要查看超过几千条最新的推文标签吗?所以你可能有一些清理机制,比如使用TTL在一段时间后删除推文,这将释放分区中的空间,使你远远低于20亿行限制。

如果您不想清理旧推文,但希望保留多年,那么您可能需要使用这样的复合分区键:

primary key ((hashtag, year), created)

这会根据标签和年份对推文进行分区,因此每年每个标签最多可存储20亿条推文。

关于按标签分区的好处是Cassandra可以保留按创建时间戳排序的标签的推文,这样就可以很容易地通过单个查询检索最新的标签。

但是,如果您的用户社区很大,那么更重要的问题就是避免热点问题。如果您只使用hashtag和一年的时间段作为分区键,那么所有读取和写入都将是该主题标签的少量副本。如果一个标签在某一天非常活跃,那么根据你正在使用的复制因素,你所有的读写操作只会转移到一个或两个节点。

如果要分散读写加载,则需要增加主题标签的基数,使其映射到多个节点。使用id作为分区键可以实现这一目标,但是这样做太过分了,因为每个推文都会在一个单独的分区中,你不会有任何排序或简单的方法来检索最新的主题标签。

因此,更好的方法是创建单独的容器或桶,如下所示:

primary key ((hashtag, bin), created)

您创建的bin数量取决于您的写入负载。假设您确定十个节点可以处理热签名的写入负载,那么bin将是0到9之间的值。

有多种方法可以设置bin编号。你可以用10做一个id的模数,或者选择0到9之间的随机数,或者从某些字段组合中生成一个哈希值,并取模10的结果。无论您选择哪种方法,请确保0到9之间的数字具有相同的可能性,以便您的数据在bin分区中均匀分布。

使用多个分区,因为您需要查询所有分箱并合并结果,因此检索主题标签的x最新推文并不容易。您可以并行异步地为主题标签的每个bin发出查询,然后在客户端合并结果。或者您可以使用IN子句执行单个查询,如下所示:

select * from posts where hashtag = 'demo' and bin IN (0,1,2,3,4,5,6,7,8,9) AND created > ...

但是Cassandra不会对单个查询的结果进行排序,因此您必须在客户端进行排序,这比单独排序查询的合并要慢。

现在在很多情况下会有很少量的主题标签,所以你可能不想为它们使用十个箱子,除非它们变热。如果是这样,你可以在你的应用程序中使它成为动态的,通常只使用bin 0,但是当发现标记很受欢迎时增加bin的数量。您可以使用bin 0中的静态列来跟踪主题标签的活动箱数。

您应该避免使用二级索引。它们在Cassandra中效率很低。