【问题标题】:Are there any major disadvantages to having multiple clustering columns in cassandra?在 cassandra 中拥有多个集群列有什么主要缺点吗?
【发布时间】:2015-03-03 04:33:27
【问题描述】:

我正在设计一个 cassandra 表,我需要能够通过其 geohash 检索行。我有一些可行的方法,但我想避免范围查询,而不是目前所能做的。

当前的表架构是这样的,geo_key 包含 geohash 字符串的前五个字符。我使用 geo_key 进行查询,然后对完整的 geohash 进行范围过滤,允许我根据 5 或更大长度的 geohash 进行前缀搜索:

CREATE TABLE georecords (geo_key text,geohash text, data text) PRIMARY KEY (geo_key, geohash))

我的想法是,我可以将 geohash 的字符存储为单独的列,允许我指定任意数量的字符,以便对 geohash 进行前缀匹配。我担心的是使用多个聚类列可能会产生什么影响:

CREATE TABLE georecords (g1 text,g2 text,g3 text,g4 text,g5 text,g6 text,g7 text,g8 text,geohash text, data text) PRIMARY KEY (g1,g2,g3,g4,g5,g6,g7,g8,geohash,pid))

(我并不真正关心分区键的基数 - g1 至少有 30 个值,我也有其他解决方法)

除了分区键的基数和额外的存储要求,如果我使用多簇列方法,我应该注意什么?

【问题讨论】:

    标签: cassandra geohashing


    【解决方案1】:

    除了分区键的基数和额外的存储要求,如果我使用多簇列方法,我应该注意什么?

    这似乎是一个需要帮助的有趣问题,因此我构建了几个具有不同 PRIMARY KEY 结构和选项的 CQL 表。然后我使用http://geohash.org/ 提出了一些端点,并插入了它们。

    aploetz@cqlsh:stackoverflow> SELECT g1, g2, g3, g4, g5, g6, g7, g8, geohash, pid, data FROm georecords3;
    
     g1 | g2 | g3 | g4 | g5 | g6 | g7 | g8 | geohash      | pid  | data
    ----+----+----+----+----+----+----+----+--------------+------+---------------
      d |  p |  8 |  9 |  v |  c |  n |  e |  dp89vcnem4n | 1001 |    Beloit, WI
      d |  p |  8 |  c |  p |  w |  g |  v |    dp8cpwgv3 | 1003 |   Harvard, IL
      d |  p |  c |  8 |  g |  e |  k |  t | dpc8gektg8w7 | 1002 | Sheboygan, WI
      9 |  x |  j |  6 |  5 |  j |  5 |  1 |    9xj65j518 | 1004 |    Denver, CO
    
    (4 rows)
    

    如您所知,Cassandra 旨在返回具有特定、精确键的数据。在该方法中使用多个聚类列有帮助,因为您可以帮助 Cassandra 快速识别您希望检索的数据。

    我唯一想改变的是,看看你是否可以在主键中不使用geohashpid。我的直觉说要摆脱pid,因为它确实不是您要查询的任何东西。它提供的唯一价值是唯一性,如果您计划多次存储相同的地理哈希,您将需要它。

    在 PRIMARY KEY 中包含 pid 会为您留下一个非键列,这样您就可以使用 WITH COMPACT STORAGE 指令。真正让您受益的唯一真正优势是节省磁盘空间,因为集群列名称不与值一起存储。从cassandra-cli 工具中查看表格时,这一点变得很明显:

    没有紧凑型存储:

    [default@stackoverflow] list georecords3;
    Using default limit of 100
    Using default cell limit of 100
    -------------------
    RowKey: d
    => (name=p:8:9:v:c:n:e:dp89vcnem4n:1001:, value=, timestamp=1428766191314431)
    => (name=p:8:9:v:c:n:e:dp89vcnem4n:1001:data, value=42656c6f69742c205749, timestamp=1428766191314431)
    => (name=p:8:c:p:w:g:v:dp8cpwgv3:1003:, value=, timestamp=1428766191382903)
    => (name=p:8:c:p:w:g:v:dp8cpwgv3:1003:data, value=486172766172642c20494c, timestamp=1428766191382903)
    => (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002:, value=, timestamp=1428766191276179)
    => (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002:data, value=536865626f7967616e2c205749, timestamp=1428766191276179)
    -------------------
    RowKey: 9
    => (name=x:j:6:5:j:5:1:9xj65j518:1004:, value=, timestamp=1428766191424701)
    => (name=x:j:6:5:j:5:1:9xj65j518:1004:data, value=44656e7665722c20434f, timestamp=1428766191424701)
    
    2 Rows Returned.
    Elapsed time: 217 msec(s).
    

    紧凑型存储:

    [default@stackoverflow] list georecords2;
    Using default limit of 100
    Using default cell limit of 100
    -------------------
    RowKey: d
    => (name=p:8:9:v:c:n:e:dp89vcnem4n:1001, value=Beloit, WI, timestamp=1428765102994932)
    => (name=p:8:c:p:w:g:v:dp8cpwgv3:1003, value=Harvard, IL, timestamp=1428765717512832)
    => (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002, value=Sheboygan, WI, timestamp=1428765102919171)
    -------------------
    RowKey: 9
    => (name=x:j:6:5:j:5:1:9xj65j518:1004, value=Denver, CO, timestamp=1428766022126266)
    
    2 Rows Returned.
    Elapsed time: 39 msec(s).
    

    但是,出于以下原因,我建议反对使用WITH COMPACT STORAGE

    • 您无法在创建表后添加或删除列。
    • 它可以防止表中有多个非键列。
    • 它确实打算用于旧的(已弃用)基于 thrift 的列族(表)建模方法,实际上不应再使用/需要了。
    • 是的,它可以节省磁盘空间,但磁盘空间很便宜,所以我认为这是一个很小的好处。

    我知道你说过“除了分区键的基数”,但无论如何我还是要在这里提一下。您会在我的示例数据集中注意到,几乎我的所有行都使用d 分区键值存储。如果我要为自己创建一个这样的应用程序,在威斯康星州/伊利诺伊州州线区域跟踪 geohashes,我肯定会遇到我的大部分数据存储在同一个分区中的问题(在我的集群中创建一个热点)。因此,了解我的用例和潜在数据后,我可能会将前三个左右的列组合成一个分区键。

    将所有内容存储在同一个分区键中的另一个问题是,每个分区最多可以存储大约 20 亿列。因此,在您的数据是否会超越该标记的情况下添加一些内容也是有意义的。显然,分区键的基数越高,遇到此问题的可能性就越小。

    通过查看您的问题,在我看来,您已经查看了您的数据并且您理解这一点......明确的“加号”。分区键中的 30 个唯一值应提供足够的分布。我只是想花一些时间来说明一下这可能是一笔多大的交易。

    不管怎样,我还想添加一个“做得很好”,因为听起来你是在正确的轨道上。

    编辑

    对我来说,仍然没有解决的问题是哪种方法可以更好地扩展,在什么情况下。

    可扩展性更依赖于您在 N 个节点上拥有多少 R 个副本。作为Cassandra scales linearly;您添加的节点越多,您的应用程序可以处理的事务就越多。纯粹从数据分布场景来看,您的第一个模型将具有更高的基数分区键,因此它将比第二个分布更均匀。但是,第一个模型在查询灵活性方面的限制要大得多。

    此外,如果您在分区内进行范围查询(我相信您说过是这样),那么第二个模型将以 非常 高性能的方式进行。分区内的所有数据都存储在同一个节点上。所以查询g1='d' AND g2='p'...等的多个结果会非常好。

    我可能只需要更多地处理数据并运行测试用例。

    这是个好主意。我想您会发现第二种模型是可行的方法(就查询灵活性和多行查询而言)。如果在单行查询方面两者之间存在性能差异,我怀疑应该可以忽略不计。

    【讨论】:

    • 这是一个很好的概要,非常感谢你。对我来说,仍然没有解决的问题是哪种方法可以更好地扩展,在哪些情况下。我可能只需要更多地处理数据并运行测试用例。
    • @Lokkju 编辑完成。您必须让我们知道结果如何。这听起来是一个很酷的项目!
    【解决方案2】:

    这是我找到的最好的 Cassandra 建模指南:http://www.ebaytechblog.com/2012/07/16/cassandra-data-modeling-best-practices-part-1/

    我已成功使用复合列(其中 6 个)来处理非常高的写入/读取负载。使用紧凑存储 (http://docs.datastax.com/en/cql/3.0/cql/cql_reference/create_table_r.html) 时没有显着的性能损失。

    紧凑存储意味着数据在内部存储在单行中,限制为您只能拥有一个数据列。无论您选择哪种数据模型,这似乎都非常适合您的应用程序,并且会最大限度地利用您的 geo_key 过滤。

    要考虑的另一个方面是列在 Cassandra 中排序。拥有更多的聚类列将提高排序速度和潜在的查找。

    但是,在您的情况下,我首先将 geohash 作为行键并打开行缓存以进行快速查找 (http://www.datastax.com/dev/blog/row-caching-in-cassandra-2-1)。如果那里缺乏性能,我会在不同的数据表示上运行性能测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-15
      • 1970-01-01
      • 2019-09-28
      • 2020-10-18
      • 1970-01-01
      • 2020-04-23
      相关资源
      最近更新 更多