【问题标题】:Cassandra for a schemaless db, 10's of millions order tables and millions of queries per dayCassandra 用于无模式数据库、每天数百万个订单表和数百万个查询
【发布时间】:2013-08-14 00:08:18
【问题描述】:

我正在建立一个数据库,具有以下特点:

  1. 每行列数可变的无模式数据库。
  2. 数千万条记录,数十列。
  3. 每天数百万次查询。
  4. 每天写入数千次。
  5. 查询将过滤多个列(不仅是键)。

我正在考虑按比例构建的 Cassandra。

我的问题是:

  1. 在这种情况下我需要水平缩放吗?
  2. Cassandra 是否支持多个键指向同一个列族?

编辑

我想确保我理解你的意思。因此,以下示例记录了我从您的回答中得到的信息:

所以,如果我们有以下列系列(它包含一些商店产品及其详细信息)

products // column-family name
{
x = {   "id":"x", // this is unique id for the row. 
    "name":"Laptop",
    "screen":"15 inch",
    "OS":"Windows"}
y = {   "id":"y", // this is unique id for the row. 
    "name":"Laptop",
    "screen":"17 inch"}
z = {   "id":"z", // this is unique id for the row. 
    "name":"Printer",
    "page per minute":"20 pages"}
}

而且,我们要添加“名称”搜索参数,我们将创建另一个具有不同行键的 CF 副本,如下所示:

products
{
"x:name:Laptop"  = {    "id":"x", 
            "name":"Laptop",
            "screen":"15 inch",
            "OS":"Windows"}
"y:name:Laptop"  = {    "id":"y", 
            "name":"Laptop",
            "screen":"17 inch"}
"z:name:Printer" = {    "id":"z", 
            "name":"Printer",
            "ppm":"20 pages"}
}

同样,为了添加“screen”搜索参数:

products
{
"x:screen:15 inch" = {  "id":"x" 
            "name":"Laptop",
            "screen":"15 inch",
            "OS":"Windows"}
"y:screen:17 inch" = {  "id":"y", 
            "name":"Laptop",
            "screen":"17 inch"}
}

但是,如果我们想基于 10 个搜索参数或它们的任意组合进行查询(如我的应用程序中的情况),那么我们将必须创建 1023 个列族副本 [(2 次方10)-1]。而且由于大多数行都会有很多搜索参数,这意味着我们需要大约 1000 倍的额外存储来对数据进行建模(以这种方式),这并不小,特别是如果我们在原始 CF 中有 10,000,000 行。

这是您建议的数据模型吗?


另一点:我不明白为什么创建二级索引会丧失或剥夺无模式模型。

【问题讨论】:

  • +1 用于在设计之前了解应用程序的粗略规模。

标签: cassandra


【解决方案1】:

Cassandra 不是您可以通过行键以外的任何内容查询的数据库。但是您可以定制您的数据模型来支持这些查询。

我们每天在 6 个 cassandra 节点集群上执行 175,000,000 次查询(很简单!),但我们只使用 row_keys 和列请求数据,因为我们已经让我们的数据模型以这种方式工作。我们不使用索引查询。

为了支持更丰富的查询,我们使用将用作搜索参数的数据对数据进行非规范化处理,以生成检索数据的键。

示例:考虑我们保存以下对象:

obj {
   id : xxx //assuming id is a unique id across the system
   p1 : value1
   p2 : value2
}

并且我们知道我们想通过这些参数中的任何一个进行搜索,然后我们将保存 obj 的副本 对于 column_names 或键如下:

"p1:value1:xxx"
"p2:value2:xxx"
"p1:value1:p2:value2:xxx" 
"xxx"

这样我们可以通过 p1 = value1, p2 =value2, p1 = value1 AND p2 = value2 或仅通过它的唯一 id xxx 来搜索 obj。

如果您不想这样做,唯一的其他选择是使用二级索引和索引查询,但这会放弃您问题的“无模式”要求。



编辑 - 一个示例。

我们想要保存对象“产品”定义为

class Products{
    string uid;
    string name;
    int screen_size; //in inches
    string os;
    string brand;
}

我们将它序列化为字符串或字节数组(我总是倾向于使用 Jackson Json 或 Protobuf ......两者都可以很好地与 cassandra 一起使用并且速度非常快)。 我们将该字节数组放入一列中。

现在是重要的部分:创建列名和行键。 假设我们要按屏幕分辨率搜索并可能按品牌过滤。 我们将屏幕尺寸的桶定义为 ["0_to15", "16_to_21", "21_up"]

给定列:

"{uid:"MI615FMDO548", name:"SFG-0098", screen_size:15, os:"Android JellyBean", brand:"Samsung"}

保存一份副本: - key = "brand:Samsung" and column_name = "screen_size:15_uid:MI615FMDO548" - key = "brand:0_to_15" and column_name = "screen_size:15_uid:MI615FMDO548"

为什么要在列名中添加 uid? 使唯一产品的所有列名称唯一。


示例第 2 部分现在假设我们添加了

"{uid:"MI615FMDO548", name:"SFG-0098", screen_size:15, os:"Android JellyBean", brand:"Samsung"}"
"{uid:"MI615FMD5589", name:"SFG-0097", screen_size:14, os:"Android JellyBean", brand:"Samsung"}"
"{uid:"MI615FMD1111", name:"SFG-0098", screen_size:17, os:"Android JellyBean", brand:"Samsung"}"
"{uid:"MI615FMDO687", name:"SFG-0095", screen_size:13, os:"Android JellyBean", brand:"Samsung"}"


我们将得到以下列族:

Products{
-Row:"brand:Samsung"
=> "screen_size:13_uid:MI615FMDO687":"{uid:"MI615FMDO687", name:"SFG-0095", screen_size:13, os:"Android JellyBean", brand:"Samsung"}"
=> "screen_size:14_uid:MI615FMD5589":"{uid:"MI615FMD5589", name:"SFG-0097", screen_size:14, os:"Android JellyBean", brand:"Samsung"}
=> "screen_size:15_uid:MI615FMDO548":"{uid:"MI615FMDO548", name:"SFG-0098", screen_size:15, os:"Android JellyBean", brand:"Samsung"}"
=> "screen_size:17_uid:MI615FMD1111":"{uid:"MI615FMD1111", name:"SFG-0098", screen_size:17, os:"Android JellyBean", brand:"Samsung"}"
-Row:"screen_size:0_to_15"
=> "brand:Samsung_uid:MI615FMDO687":"{uid:"MI615FMDO687", name:"SFG-0095", screen_size:13, os:"Android JellyBean", brand:"Samsung"}"
=> "brand:Samsung_uid:MI615FMD5589":"{uid:"MI615FMD5589", name:"SFG-0097", screen_size:14, os:"Android JellyBean", brand:"Samsung"}
=> "brand:Samsung_uid:MI615FMDO548":"{uid:"MI615FMDO548", name:"SFG-0098", screen_size:15, os:"Android JellyBean", brand:"Samsung"}"
-Row:"screen_size:16_to_17"
=> "brand:Samsung_uid:MI615FMD1111":"{uid:"MI615FMD1111", name:"SFG-0098", screen_size:17, os:"Android JellyBean", brand:"Samsung"}"
-Row:"uid:MI615FMDO687"
=> "product":"{uid:"MI615FMDO687", name:"SFG-0095", screen_size:13, os:"Android JellyBean", brand:"Samsung"}"
-Row:"uid:MI615FMD5589"
=> "product":"{uid:"MI615FMD5589", name:"SFG-0097", screen_size:14, os:"Android JellyBean", brand:"Samsung"}
-Row:"uid:MI615FMDO548"
=> "product":"{uid:"MI615FMDO548", name:"SFG-0098", screen_size:15, os:"Android JellyBean", brand:"Samsung"}"
-Row:"uid:MI615FMD1111"
=> "product":"{uid:"MI615FMD1111", name:"SFG-0098", screen_size:17, os:"Android JellyBean", brand:"Samsung"}"
}

现在通过跨列名称使用范围查询,您可以按品牌和屏幕大小进行搜索。



希望对你有用

【讨论】:

  • 我相信它很有用。但是,请查看我在上述问题中的新编辑。谢谢。
  • 抱歉,您的编辑/评论回复晚了。我想你把它弄反了。如果您将 cassandra 集群设置为使用随机分区器(如果您想要一个平衡的令牌环,建议这样做),您将无法有效地搜索跨行键。您必须以某种方式存储您的产品,这些存储桶的名称将是行键(您可以使用品牌、一系列屏幕尺寸或任何您喜欢的东西),在这些行中,您可以使用我的方法来创建列名,所以它们被排序以允许您在行中搜索所需的值。
猜你喜欢
  • 2020-03-07
  • 2011-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-15
  • 1970-01-01
  • 2018-12-21
  • 2011-08-15
相关资源
最近更新 更多