Cassandra 存储内部
Cassandra storage internal
我试图了解当以 CQL 样式插入行(列)时,存储引擎级别内部到底发生了什么 table。
CREATE TABLE log_date (
userid bigint,
time timeuuid,
category text,
subcategory text,
itemid text,
count int,
price int,
PRIMARY KEY ((userid), time) - #1
PRIMARY KEY ((userid), time, category, subcategory, itemid, count, price) - #2
);
假设我有一个像上面那样的table。
在#1 的情况下,CQL 行将在存储中生成 6(或 5?)列。
在#2 的情况下,一个 CQL 行将在存储中生成一个非常复杂的列。
我想知道将日志存储到 Cassandra 中的更有效方法是什么。
请重点关注给定的两种情况。
我不需要任何实时读取。只是写作。
如果您想建议其他选项,请参考以下内容。
我选择 Cassandra 存储日志的原因是
- 线性可扩展性,适合大量写入。
- 它有 CQL 模式。我真的更喜欢有一个模式。
- 似乎对 Spark 的支持还不错。 Datastax 的 cassandra-spark 连接器似乎具有数据本地化意识。
I'm trying to understand what exactly happens internally in storage engine level when a row(columns) is inserted in a CQL style table.
假设我用你的两个 PRIMARY KEY 建表,并插入一些数据:
aploetz@cqlsh:Whosebug2> SELECT userid, time, dateof(time), category, subcategory, itemid, count, price FROM log_date1;
userid | time | dateof(time) | category | subcategory | itemid | count | price
--------+--------------------------------------+--------------------------+----------+----------------+-------------------+-------+-------
1002 | e2f67ec0-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:48:20-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1002 | 15d0fd20-f589-11e4-ade7-21b264d4c94d | 2015-05-08 08:49:45-0500 | Audio | Headphones | 228-5-44343-344-5 | 1 | 4799
1001 | 32671010-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:43:23-0500 | Books | Computer Books | 978-1-78398-912-6 | 1 | 2200
1001 | 74ad4f70-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:45:14-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1001 | a3e1f750-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:46:34-0500 | Books | Computer Books | 977-8-78998-466-4 | 1 | 599
(5 rows)
aploetz@cqlsh:Whosebug2> SELECT userid, time, dateof(time), category, subcategory, itemid, count, price FROM log_date2;
userid | time | dateof(time) | category | subcategory | itemid | count | price
--------+--------------------------------------+--------------------------+----------+----------------+-------------------+-------+-------
1002 | e2f67ec0-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:48:20-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1002 | 15d0fd20-f589-11e4-ade7-21b264d4c94d | 2015-05-08 08:49:45-0500 | Audio | Headphones | 228-5-44343-344-5 | 1 | 4799
1001 | 32671010-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:43:23-0500 | Books | Computer Books | 978-1-78398-912-6 | 1 | 2200
1001 | 74ad4f70-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:45:14-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1001 | a3e1f750-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:46:34-0500 | Books | Computer Books | 977-8-78998-466-4 | 1 | 599
(5 rows)
通过 cqlsh
看起来几乎一样。那么让我们从 cassandra-cli
看一下,并查询 userid
1002:
的所有行
RowKey: 1002
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:, value=, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:category, value=426f6f6b73, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:count, value=00000001, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:itemid, value=3637382d322d34343339382d3331322d39, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:price, value=0000031e, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:subcategory, value=4e6f76656c73, timestamp=1431092900008568)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:, value=, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:category, value=417564696f, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:count, value=00000001, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:itemid, value=3232382d352d34343334332d3334342d35, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:price, value=000012bf, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:subcategory, value=4865616470686f6e6573, timestamp=1431092985326774)
很简单吧?我们将 userid
1002 视为 RowKey,将 time
的聚类列视为列键。接下来是每个列键 (time
) 的所有列。而且我相信您的第一个实例会生成 6 列,因为我很确定其中包含列键的占位符,因为您的 PRIMARY KEY 可能指向一个空值(就像您的第二个示例键一样)。
但是 userid
1002 的第二个版本呢?
RowKey: 1002
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:Books:Novels:678-2-44398-312-9:1:798:, value=, timestamp=1431093011349994)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:Audio:Headphones:228-5-44343-344-5:1:4799:, value=, timestamp=1431093011360402)
为 RowKey 1002 返回两列,一列对应我们的列(集群)键的每个唯一组合,具有空值(如上所述)。
那么这对您来说意味着什么?好吧,有几件事:
- 这应该告诉您 Cassandra 中的 PRIMARY KEY 确保唯一性。因此,如果您决定需要更新诸如
category
或 subcategory
(第二个示例)之类的键值,除非您删除并重新创建该行,否则您真的不能这样做。虽然从日志记录的角度来看,这可能没问题。
- Cassandra 将特定 partition/row 键 (
userid
) 的所有数据存储在一起,按列(集群)键排序。如果您担心数据的查询和排序,请务必了解您必须查询每个特定的 userid
排序顺序才能有所不同。
- 我看到的最大问题是,现在您正在为无限制的列增长做准备。 Partition/row 键最多可支持 20 亿列,因此您的第二个示例将对您的帮助最大。如果您认为您的某些
userid
可能会超过该值,则可以将 "date bucket" 实现为附加分区键(例如,如果您知道 userid
永远不会超过 20 亿在一年内,或其他什么)。
在我看来,您的第二个选项可能是更好的选择。但老实说,对于你正在做的事情,它们中的任何一个都可能工作正常。
我试图了解当以 CQL 样式插入行(列)时,存储引擎级别内部到底发生了什么 table。
CREATE TABLE log_date (
userid bigint,
time timeuuid,
category text,
subcategory text,
itemid text,
count int,
price int,
PRIMARY KEY ((userid), time) - #1
PRIMARY KEY ((userid), time, category, subcategory, itemid, count, price) - #2
);
假设我有一个像上面那样的table。
在#1 的情况下,CQL 行将在存储中生成 6(或 5?)列。
在#2 的情况下,一个 CQL 行将在存储中生成一个非常复杂的列。
我想知道将日志存储到 Cassandra 中的更有效方法是什么。
请重点关注给定的两种情况。
我不需要任何实时读取。只是写作。
如果您想建议其他选项,请参考以下内容。
我选择 Cassandra 存储日志的原因是
- 线性可扩展性,适合大量写入。
- 它有 CQL 模式。我真的更喜欢有一个模式。
- 似乎对 Spark 的支持还不错。 Datastax 的 cassandra-spark 连接器似乎具有数据本地化意识。
I'm trying to understand what exactly happens internally in storage engine level when a row(columns) is inserted in a CQL style table.
假设我用你的两个 PRIMARY KEY 建表,并插入一些数据:
aploetz@cqlsh:Whosebug2> SELECT userid, time, dateof(time), category, subcategory, itemid, count, price FROM log_date1;
userid | time | dateof(time) | category | subcategory | itemid | count | price
--------+--------------------------------------+--------------------------+----------+----------------+-------------------+-------+-------
1002 | e2f67ec0-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:48:20-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1002 | 15d0fd20-f589-11e4-ade7-21b264d4c94d | 2015-05-08 08:49:45-0500 | Audio | Headphones | 228-5-44343-344-5 | 1 | 4799
1001 | 32671010-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:43:23-0500 | Books | Computer Books | 978-1-78398-912-6 | 1 | 2200
1001 | 74ad4f70-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:45:14-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1001 | a3e1f750-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:46:34-0500 | Books | Computer Books | 977-8-78998-466-4 | 1 | 599
(5 rows)
aploetz@cqlsh:Whosebug2> SELECT userid, time, dateof(time), category, subcategory, itemid, count, price FROM log_date2;
userid | time | dateof(time) | category | subcategory | itemid | count | price
--------+--------------------------------------+--------------------------+----------+----------------+-------------------+-------+-------
1002 | e2f67ec0-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:48:20-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1002 | 15d0fd20-f589-11e4-ade7-21b264d4c94d | 2015-05-08 08:49:45-0500 | Audio | Headphones | 228-5-44343-344-5 | 1 | 4799
1001 | 32671010-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:43:23-0500 | Books | Computer Books | 978-1-78398-912-6 | 1 | 2200
1001 | 74ad4f70-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:45:14-0500 | Books | Novels | 678-2-44398-312-9 | 1 | 798
1001 | a3e1f750-f588-11e4-ade7-21b264d4c94d | 2015-05-08 08:46:34-0500 | Books | Computer Books | 977-8-78998-466-4 | 1 | 599
(5 rows)
通过 cqlsh
看起来几乎一样。那么让我们从 cassandra-cli
看一下,并查询 userid
1002:
RowKey: 1002
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:, value=, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:category, value=426f6f6b73, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:count, value=00000001, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:itemid, value=3637382d322d34343339382d3331322d39, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:price, value=0000031e, timestamp=1431092900008568)
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:subcategory, value=4e6f76656c73, timestamp=1431092900008568)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:, value=, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:category, value=417564696f, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:count, value=00000001, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:itemid, value=3232382d352d34343334332d3334342d35, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:price, value=000012bf, timestamp=1431092985326774)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:subcategory, value=4865616470686f6e6573, timestamp=1431092985326774)
很简单吧?我们将 userid
1002 视为 RowKey,将 time
的聚类列视为列键。接下来是每个列键 (time
) 的所有列。而且我相信您的第一个实例会生成 6 列,因为我很确定其中包含列键的占位符,因为您的 PRIMARY KEY 可能指向一个空值(就像您的第二个示例键一样)。
但是 userid
1002 的第二个版本呢?
RowKey: 1002
=> (name=e2f67ec0-f588-11e4-ade7-21b264d4c94d:Books:Novels:678-2-44398-312-9:1:798:, value=, timestamp=1431093011349994)
=> (name=15d0fd20-f589-11e4-ade7-21b264d4c94d:Audio:Headphones:228-5-44343-344-5:1:4799:, value=, timestamp=1431093011360402)
为 RowKey 1002 返回两列,一列对应我们的列(集群)键的每个唯一组合,具有空值(如上所述)。
那么这对您来说意味着什么?好吧,有几件事:
- 这应该告诉您 Cassandra 中的 PRIMARY KEY 确保唯一性。因此,如果您决定需要更新诸如
category
或subcategory
(第二个示例)之类的键值,除非您删除并重新创建该行,否则您真的不能这样做。虽然从日志记录的角度来看,这可能没问题。 - Cassandra 将特定 partition/row 键 (
userid
) 的所有数据存储在一起,按列(集群)键排序。如果您担心数据的查询和排序,请务必了解您必须查询每个特定的userid
排序顺序才能有所不同。 - 我看到的最大问题是,现在您正在为无限制的列增长做准备。 Partition/row 键最多可支持 20 亿列,因此您的第二个示例将对您的帮助最大。如果您认为您的某些
userid
可能会超过该值,则可以将 "date bucket" 实现为附加分区键(例如,如果您知道userid
永远不会超过 20 亿在一年内,或其他什么)。
在我看来,您的第二个选项可能是更好的选择。但老实说,对于你正在做的事情,它们中的任何一个都可能工作正常。