3

按照ebay 技术博客datastax 开发人员博客中的指示,我在 Cassandra 1.2 中对一些事件日志数据进行建模。作为分区键,我使用“ddmmyyhh|bucket”,其中 bucket 是介于 0 和集群中节点数之间的任意数字。

数据模型

cqlsh:Log> CREATE TABLE transactions (yymmddhh varchar, bucket int, rId int, created timeuuid, data map, PRIMARY KEY((yymmddhh, bucket), created) );

(rId 标识触发事件的资源。)(映射是从 JSON 派生的键值对;键更改,但变化不大)

我假设这会转化为一个复合主键/行键,每小时有 X 个存储桶。我的列名比timeuuids。查询此数据模型按预期工作(我可以查询时间范围。)

问题在于性能:插入新行的时间不断增加。所以我在做某事。错了,但无法确定问题所在。

当我使用 timeuuid 作为行键的一部分时,性能在较高水平上保持稳定,但这会阻止我查询它(没有行键的查询当然会抛出有关“过滤”的错误消息)。

有什么帮助吗?谢谢!

更新

从映射数据类型切换到预定义的列名可以缓解这个问题。现在插入时间似乎保持在每次插入 <0.005 秒左右。

核心问题仍然存在: 我如何高效地使用“map”数据类型?对于数千个插入只有轻微变化的键来说,什么是一种有效的方法。

我在地图中使用数据的键大多保持不变。我理解datastax文档(由于声誉限制无法发布链接,抱歉,但很容易找到)说每个键创建一个额外的列 - 或者它是否为每个“地图”创建一个新列??那将是……我很难相信。

4

2 回答 2

2

我建议你对你的行建模有点不同。在您最终可能会在其中包含太多元素的情况下,这些集合并不是很好用。原因是 Cassandra 二进制协议的限制,它使用两个字节来表示集合中的元素数量。这意味着如果您的集合中包含超过 2^16 个元素,则 size 字段将溢出,即使服务器将所有元素发送回客户端,客户端也只会看到第N % 2^16一个元素(因此,如果您有 2^16 + 3 个元素,它会在客户端看起来好像只有 3 个元素)。

如果没有将这么多元素放入您的集合的风险,您可以忽略此建议。我不认为使用集合会给您带来更差的性能,我不确定这会如何发生。

CQL3 集合基本上只是存储模型之上的 hack(我并不是指任何负面意义上的 hack),您可以自己制作不受上述限制约束的类似 MAP 的行:

CREATE TABLE transactions (
  yymmddhh VARCHAR,
  bucket INT,
  created TIMEUUID,
  rId INT,
  key VARCHAR,
  value VARCHAR,
  PRIMARY KEY ((yymmddhh, bucket), created, rId, key)
)

(请注意,我将rId映射键移动到主键中,我不知道是什么rId,但我认为这是正确的)

与使用 MAP 相比,这有两个缺点:它要求您在查询数据时重新组合映射(每个映射条目会返回一行),并且由于 C* 将插入一些额外的列,因此它使用了更多的空间,但好处是收集太大的收藏没有问题。

最后,这在很大程度上取决于您要如何查询数据。不要优化插入,优化读取。例如:如果您不需要每次都读回整个映射,但通常只从中读取一两个键,则将键放在分区/行键中,并且每个键有一个单独的分区/行(这假设键集是固定的,因此您知道要查询什么,正如我所说:这在很大程度上取决于您要如何查询数据)。

您还在评论中提到,当您将存储桶的数量从三个 (0-2) 增加到 300 (0-299) 时,性能会有所提高。这样做的原因是您可以在整个集群中更均匀地分布负载。当您有一个基于时间的分区/行键时,例如您的yymmddhh,总会有一个热分区,所有写入都在其中进行(它全天移动,但在任何给定时刻它只会命中一个节点)。您正确地为列/单元格添加了一个平滑因子bucket,但只有三个值,至少两个最终在同一个物理节点上的可能性太高。有了三百个,您将获得更好的传播。

于 2013-06-15T11:39:16.977 回答
0

使用yymmddhh作为rowkey,bucket+timeUUID作为列名,每个bucket有20条记录或固定记录数,bucket可以使用counter cloumn family管理

于 2013-06-13T10:38:58.460 回答