【问题标题】:Google Bigtable - how to store data to be able then to query it by country, city and date?Google Bigtable - 如何存储数据以便能够按国家、城市和日期查询?
【发布时间】:2019-08-13 17:10:17
【问题描述】:

我正在为我的 Bigtable 寻找一个最佳方案,以通过指定年份(或完整日期)、国家和(或)城市来满足查询数据的要求。我曾考虑将我的行键命名为2019.us.NYC,然后通过前缀查询它,但这是一个坏主意,因为它只会将我的所有数据存储在一个节点上,直到 2020 年到来,而不是共享给其他节点。有任何想法吗?也许有人已经有了这样的案例?这里的瓶颈是每秒将有大约 50 000 000 条新行。

编辑:也许使用 BigQuery 更好?

【问题讨论】:

  • 回答您的最后一个问题,BigQuery 对流式插入 (cloud.google.com/bigquery/quotas#streaming_inserts) 有配额:每个项目每秒 100'000 行,因此 Bigtable 可能是您想要使用的数据库。您能否阐明您的数据查询要求?在您的问题中,这些是排他性的 还是,或者您可以查询完整日期和国家/地区吗?您需要低延迟来进行数据访问吗?还请提供您要存储的数据示例,以帮助您设计 Bigtable 架构。
  • @norbjd 首先感谢您的帮助。要求是至少能够按指定年份和国家/地区查询数据。另外可以指定月份、日期和城市名称。低延迟非常重要。我计划存储包含我需要的所有内容的简单 json 值,但如果我能够将数据直接存储到表族中会更好。
  • @norbjd 在 MySQL 表中,这个查询看起来像这样:SELECT * FROM my_table WHERE country = 'us' AND city = 'new_york' AND date = '2019-08-12' ORDER BY id DESC LIMIT 100 或:SELECT * FROM my_table WHERE country = 'de' AND city = 'berlin' AND YEAR(date) = '2017' ORDER BY id DESC LIMIT 100
  • BigTable 强制使用单个键。您希望最后有一个组合键和另一个值。因此,可能类似于“2019.us.Nyc.{guid}”,其中 guid 是您为每个值创建的一些唯一标识符。然后,您可以使用一个简单的范围运算符,如果您想要整个组,它应该能够尽可能快。然后您可以在 '2019.us.nyc.{empty-guid}' 和 '2019.us 之间进行。 nyc.{max-guid}' 查找所有数据,同时仍然具有唯一行。查看范围过滤器cloud.google.com/bigquery/external-data-bigtable
  • 回答上面的评论,使用2019.us.Nyc.{guid}作为rowkey会导致Bigtable节点热点(在同一个节点上连续写入),因为行键将是连续的,正如@Mmh1正确理解的那样并在他的问题中写道。此外,如果需要低延迟读取,从 Bigquery 中查询数据以访问 Bigtable 数据可能不是解决方案。

标签: google-cloud-bigtable


【解决方案1】:

根据您的要求,以下是一个可能的解决方案:

  • 每秒 50'000'000 次写入
  • 数据访问延迟低
  • 查询总是包含yearcountry,可选monthdaycity

year + country

由于yearcountry 始终出现在您的查询中,因此它们必须位于行键的开头,例如:

  • 2018#de
  • 2019#de
  • 2019#us

(这里我用#定界,但是如果yearcountry总是分别定义在4个和2个字符上可能就没用了。你可以去掉它来节省一个字节!)。

month + day + city

因为monthdaycity是可选的,它们也可以出现在行键上,而是出现在最后:

  • 2018#de#0610#frankfurt
  • 2019#de#0115#berlin
  • 2019#us#0813#nyc

我建议您根据需要重新排序元素(如果使用yearcountrycity 的查询是最常见的,那么顺序应该是year#country#city)。只有您可以知道最频繁的查询。总是需要design your row key with your queries in mind

避免热点

但是,正如您在问题中所建议的那样,这种行键设计可能会导致 Bigtable 节点热点(所有写入单个节点,因为行键是连续的)。为了解决这个问题并确保节点之间行键的完美分布,我建议您使用分桶。

对于每次写入,您可以生成一个随机数(0 到 8 之间,例如如果您想要 8 个存储桶),并将该存储桶编号添加到您的行键中。例如:

  • 3#2018#de#0610#frankfurt
  • 2#2019#de#0115#berlin
  • 7#2019#us#0813#nyc

然后,您将确保在编写时您的密钥将正确分布在您的 Bigtable 节点中。

您可以查看此链接,了解如何在 HBase(Bigtable 等效项)上执行此操作:https://hbase.apache.org/book.html#schema.casestudies.log_timeseries.tslead

查询数据

但是由于这种分桶(或加盐),您需要更改查询表的方式。如果您想要美国 2019 年的所有数据,则需要执行 8 次扫描(每个存储桶一次):

  • 开始键:0#2019#us#,结束键:0#2019#us~
  • 开始键:1#2019#us#,结束键:1#2019#us~
  • 开始键:2#2019#us#,结束键:2#2019#us~
  • 开始键:3#2019#us#,结束键:3#2019#us~
  • 开始键:4#2019#us#,结束键:4#2019#us~
  • 开始键:5#2019#us#,结束键:5#2019#us~
  • 开始键:6#2019#us#,结束键:6#2019#us~
  • 开始键:7#2019#us#,结束键:7#2019#us~

(我在结束键的末尾使用了~,因为ASCII 表中的~ 是在# 之后的所有可能字符之后。例如,对于第一次扫描,这可以确保所有行键开始由0#2019#us# 检索)

这些扫描可以并行执行以获得最佳性能。

扫描是在 Bigtable 中查询数据的最高效方式。您还可以使用一些过滤器(例如FuzzyRowFilter 使用特定正则表达式查询行键),但扫描肯定会给您带来更好的延迟。您还可以执行扫描并在扫描后使用过滤器(例如,要检索 us 中的 2019nyc 的所有数据,需要过滤器以仅获取带有 city = nyc 的行)。

结论

因此,基于这些元素,我将设计我的密钥:

<bucket_number>#<year>#<country>#<month><day>#<city>

使用扫描查询我的表。如果所有字段都具有固定长度,则分隔符(此处为#)是无用的。

如果您有足够数量的 &lt;country&gt; 值来将密钥分配到不同的节点,您也可以有一些不分桶的变体:

<year>#<country>#<month><day>#<city>

或:

<country>#<year>#<month><day>#<city>

总之,在设计 Bigtable 行键时总是需要权衡取舍。通过使用分桶,您始终可以避免热点,但查询数据的方式更加复杂。但是,根据您的要求(许多写),这就是我要做的。

您还可以根据 Bigtable 集群中的节点数来更改存储桶的数量。如果您有超过 8 个节点,我建议您创建更多存储桶。理想情况下,1 个桶 = 1 个节点,但一个节点可以轻松包含多个桶。

我建议与其他人一起测试这个关键设计,并在实际条件 (PoC) 中对它们进行基准测试。您可以使用 Bigtable Key Visualizer 检查您的密钥在集群中的分布情况。

【讨论】:

  • 依靠过滤器获取一小部分行通常是个坏主意。 Bigtable 仍然需要读取您扫描范围的所有数据,然后再应用过滤器。这不会避免在过滤掉的行中出现热点。
  • 此外,连续的行键通常不会导致节点的热点,因为 Bigtable 将继续拆分平板电脑以减少负载并在节点之间打乱平板电脑以分散负载。当频繁使用单个行/键时,通常会发生热点。
  • 回答您关于过滤的评论:您是对的,这就是为什么我建议在之前扫描数据,然后在如果需要之后进行过滤。但有时,过滤是必要的。在我使用city 的示例中:如果city 位于键的末尾,并且如果我们不知道countrycity 之间的内容,那么唯一的可能性就是过滤。我们不能依靠扫描来检索与城市相关的数据,但我们可以在第一步中进行扫描以检索所需年份和国家/地区的所有数据。
  • 如果有足够的country 值来确保正确分配行键,确实可以避免分桶。我已经相应地更新了答案。如果没有更高的精度,在处理如此高的写入吞吐量时,分桶仍然是一个好主意:即使 Bigtable 自动执行拆分,此操作也有成本,并且(尽可能)避免它们总是更好。
  • @norbjd &lt;country&gt;#&lt;year&gt;#&lt;month&gt;&lt;day&gt;#&lt;city&gt; - 如果有 500 个节点和 200 个国家,它不会导致热点吗?我不明白它是如何工作的......我拥有的节点越多,获得热点的机会就越少?
猜你喜欢
  • 1970-01-01
  • 2014-09-08
  • 2017-09-02
  • 1970-01-01
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
相关资源
最近更新 更多