按照an ebay tech blog和a datastax developers blog中的指针,我在Cassandra 1.2中为一些事件日志数据建模。作为分区键,我使用“ddmmyyhh | bucket”,其中bucket是0到集群中节点数之间的任意数字。
数据模型
cqlsh:日志与GT; CREATE TABLE事务(yymmddhh varchar,bucket int, rId int,创建timeuuid,数据图,PRIMARY KEY((yymmddhh,bucket),created));
(rId标识触发事件的资源。) (map是从JSON派生的键值对;键更改,但不多)
我认为这会转化为每小时X桶的复合主/行密钥。 我的列名不是timeuuids。查询此数据模型按预期工作(我可以查询时间范围。)
问题在于性能:插入新行的时间不断增加。 所以我正在做s.th.错了,但无法查明问题。
当我使用timeuuid作为行键的一部分时,性能在高级别上保持稳定,但这会阻止我查询它(没有行键的查询当然会抛出有关“过滤”的错误消息)。
有任何帮助吗?谢谢!
从地图数据类型切换到预定义的列名称可以缓解此问题。现在,插入时间似乎保持在每个插入物大约<0.005s。
核心问题仍然存在: 我对“map”数据类型的使用效率如何?对于成千上万的插入物而言,只有轻微的键变化,这将是一种有效的方法。
我在地图中使用数据的密钥大多保持不变。我理解datastax文档(由于声誉限制不能发布链接,抱歉,但很容易找到),说每个键创建一个额外的列 - 或者它是否每个“地图”创建一个新列?那将是......很难相信我。
答案 0 :(得分:2)
我建议您对行进行一些不同的建模。在您可能最终使用过多元素的情况下,这些集合不是很好用。原因是Cassandra二进制协议的限制,它使用两个字节来表示集合中的元素数量。这意味着如果您的集合中包含超过2 ^ 16个元素,则size字段将溢出,即使服务器将所有元素发送回客户端,客户端也只会看到N % 2^16
第一个元素(如果你有2 ^ 16 + 3个元素,它会向客户看,好像只有3个元素。)
如果没有将多少元素放入集合的风险,您可以忽略此建议。我不认为使用收藏会给你带来更差的表现,我不确定会发生什么。
CQL3集合基本上只是存储模型之上的黑客攻击(我并不是指任何负面意义上的黑客攻击),你可以创建一个不受上述限制的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 *会插入一些额外的列,但好处是获得太大的集合没有问题。
最后,它很大程度上取决于您想要如何查询数据。不优化插入,优化读取。例如:如果您不需要每次都回读整个映射,但通常只需从中读取一个或两个键,则将密钥放入分区/行键中,并为每个键分配一个单独的行/行(这假设这组密钥将被修复,因此您知道要查询的内容,正如我所说:这很大程度上取决于您想要查询数据的方式。)
您还在评论中提到,当您将存储桶数量从3(0-2)增加到300(0-299)时,性能得到了提升。这样做的原因是您可以在群集中更均匀地分布负载。如果你有一个基于时间的分区/行密钥,就像你的yymmddhh
一样,总会有一个热门分区,所有写入都会进行(它会在一天中移动,但在任何给定时刻它只会触及一个节点)。您正确地使用bucket
列/单元格添加了平滑因子,但只有三个值,至少两个在同一物理节点上结束的可能性太高。有三百个你会有更好的传播。
答案 1 :(得分:0)
使用yymmddhh作为rowkey和bucket + timeUUID作为列名,其中每个桶有20个或修复no记录,可以使用counter cloumn family管理桶