Bigtable 性能影响列族

Bigtable performance influence column families

我们目前正在调查使用多个列族对我们的大table 查询性能的影响。我们发现将列拆分为多个列族并不会提高性能。有没有人有过类似的经历?

关于我们的基准设置的更多细节。目前,我们生产中的每一行 table 包含大约 5 列,每列包含 0.1 到 1 KB 的数据。所有列都存储在一个列族中。当执行行键范围过滤器(returns 平均 340 行)并应用列正则表达式过滤器(每行 returns 只有 1 列)时,查询平均需要 23.3 毫秒。我们创建了一些测试 table,其中我们将每行的 columns/data 数量增加了 5 倍。在测试 table 1 中,我们将所有内容都保留在一个列族中。正如预期的那样,这将同一查询的查询时间增加到 40.6 毫秒。在test table 2中,我们将原始数据保留在一个列族中,但将额外的数据放入另一个列族中。当查询包含原始数据的列族时(因此包含与原始table相同数量的数据),查询时间平均为 44.3ms。因此,当使用更多的列族时,性能甚至会下降。

这与我们的预期完全相反。例如。 bigtable 文档中提到了这一点 (https://cloud.google.com/bigtable/docs/schema-design#column_families)

Grouping data into column families allows you to retrieve data from a single family, or multiple families, rather than retrieving all of the data in each row. Group data as closely as you can to get just the information that you need, but no more, in your most frequent API calls.

谁能解释我们的发现?

benchmark results


(编辑:添加了更多细节)

单行内容:

Table 1:

Table 2:

我们正在执行的基准测试使用的是 go 客户端。调用 API 的代码基本上如下所示:

filter = bigtable.ChainFilters(bigtable.FamilyFilter(request.ColumnFamily),
            bigtable.ColumnFilter(colPattern), bigtable.LatestNFilter(1))
tbl := bf.Client.Open(table)
rr := bigtable.NewRange(request.RowKeyStart, request.RowKeyEnd)
err = tbl.ReadRows(c, rr, func(row bigtable.Row) bool {return true}, bigtable.RowFilter(filter))

如果您每行检索 X 个单元格,那么无论这些单元格是在 X 个单独的列族中还是在具有 X 列限定符的 1 个列族中,都不会产生重大的性能差异。

如果您实际上只需要具有特定用途的行的单元格,就会出现性能差异 - 您可以避免为该行选择所有单元格,而是只获取一个列族(通过指定 filter on the ReadRow call)


一个更重要的因素是简单地选择一个能够准确描述您的数据的架构。如果你这样做,上述类型的任何收益都会自然而然地出现。您还将避免达到 100 个列族的推荐限制。

例如:假设您正在编写排行榜软件,并且您想要存储玩家在每场比赛中的得分以及一些个人详细信息。您的架构可能是:

  • 行键:用户名
  • 列族user_info
    • 列限定符 full_name
    • 列限定符 password_hash
  • 列族game_scores
    • 列限定符 candy_royale
    • 列限定符 clash_of_tanks

将每个游戏存储为 game_scores 列族中的单独列允许一次获取用户的所有分数而无需同时获取 user_info,允许保持列族的数量可管理, 允许独立地为每场比赛记录时间序列的分数,并从镜像数据的性质中获得其他好处。

在多个列族上拆分数据时性能没有提高的原因是它们存储在同一个 "locality group",即文件中。在内部 Google 确实提供了将不同列族拆分到不同位置组的可能性,但这并没有在他们的托管 Cloud Bigtable 服务中公开。查看 上的评论。