【问题标题】:HBase schema for storing timeseries user data用于存储时间序列用户数据的 HBase 模式
【发布时间】:2014-01-03 21:00:13
【问题描述】:

我目前正在开发一种将用户当前位置历史存储到 HBase 表中的解决方案原型。 (假设有数亿用户)。 每个用户对位置的试用都存储在 HBase 表中。 然后将这些位置跟踪用作少数离线数据分析工作的一部分。

以下是两种主要的数据访问模式:

  1. 我应该能够从存储的位置试验中扫描特定用户的全部或部分位置(基于时间范围)。

  2. 对于离线数据分析,我应该能够扫描所有位置 一个时间范围内的所有用户。

鉴于上述要求,我想出了以下行键设计:

<uid>_<timestamp>

其中“uid”表示用户 ID,“timestamp”表示检测并保存位置的时间。

使用这种行键设计,实现访问模式 #1 很简单 - 扫描请求可以有一个开始键和结束键,并将给定的时间戳附加到特定的 uid。

但是,棘手的部分是访问模式 #2,我正在寻求 HBase 专家的帮助。 因为,我需要扫描所有用户说过去 6 个月,我最终不会使用任何键进行扫描操作。这会影响扫描整个 HBase 表。我觉得这是低效的。此外,我的数据量预计会以 2K/秒的写入负载更快地增长。

我查看了开放论坛中许多人指出的 OpenTSDB。但我无法将该解决方案与我的数据访问模式联系起来。

我正在寻求帮助以优化此架构,从而避免全表扫描。

【问题讨论】:

  • 你对时间戳有限制吗?也就是说,您将只保留过去 6 个月内的最后一个时间戳?
  • 是的。我可能会保留过去一年的数据。我会这样配置 TTL。
  • 对于数据访问模式 #2 - 时间范围应该灵活还是固定?
  • 时间范围类似于 - 过去一周或几周,过去一或几个月。

标签: hbase


【解决方案1】:

您可以将每个位置存储在其自己的列中,而不是将每个位置点存储在一行中,并且 TTL 为一年。这与 OpenTSDB 对指标进行分桶的方式类似,在特定时间窗口内,指标的每个读数都存储在单独的列中。

此架构允许您扫描所有用户和扫描作业内部,手动过滤掉您不关心的日期。这仍然是全表扫描,但仅针对您的用户集,而不是您所有位置的集。

此架构还具有允许用户访问其整个位置历史记录的优点,即只允许一次获取或小扫描(见下文)。

此架构的缺点在于每个用户的行大小。如果每个用户都有几百或几千个数据点,你应该没问题。但是,如果每个用户都有数百万个位置,那么您的行大小可能会增长到与您所在区域相同的大小。由于 HBase 从不跨区域拆分行,因此您最终会得到由单行组成的区域,这不是最优的。

要解决此问题,您需要像 OpenTSDB 一样为每个用户实现自己的签入数据桶。假设每个桶是 uid+weekOfTheYear+year。存储桶粒度在很大程度上取决于用户添加位置数据的频率。这会为每个用户创建多行,因此需要对给定用户的每个存储桶进行扫描。要访问特定日期范围的数据,只需使用扫描仪内置的时间戳过滤即可。

【讨论】:

    【解决方案2】:

    您可以做的一件简单的事情是在密钥中提升一些时间 - 例如在这种情况下添加月份前缀,常规查询可能需要查看多个扫描(假设在常见用途中您只需要最新记录而不是大多数情况下它不会成为问题),但运行时间较长将受到月份的限制。

    顺便说一句,如果在常规使用中您想要最新的记录,您可能希望存储从最新到最旧的日期(maxlong - 时间戳),以便对时间范围的查询更快

    【讨论】:

    • 对不起,我没能听懂你的回答。当您说在键中添加月份前缀时,您是什么意思?当我需要获取一个时间范围内的所有用户记录时,这将如何避免全表扫描?
    • Yearmonth_user_timestamp 例如201312_01_123456788.. 所以您只需扫描您需要的月份,并在大型扫描中跳过不需要的月份
    • 我担心这个行键“201312_[user]_[timestamp]”可能会导致写入热点,因为所有写入都命中同一个区域服务器。
    • 您是否获得热点取决于您的分区 - 您可以为每个区域划分一些用户范围的客户。顺便说一句,2K/秒并不是很高(我们正在编写超过 10K 个事件,每个节点每秒 1K 大小
    • 根据我最初的建议,由于 uid 是行键的一部分,因此分区要简单得多。由于 UID 往往具有良好的分布,我有一个非常简单的分区策略来拆分 ascii 字符。根据您的建议,我们可能需要将其更改为其他内容。您能否详细说明如何将 格式保留在行键的前面?
    【解决方案3】:

    就我个人而言,我会避免在行键中使用基于时间的前缀。

    让我为您指出另一个方向,您能否承受数据重复?

    如果答案是“是”,只需创建另一个表,其中包含您的作业所需的最少数据并将 TTL 设置为 6 个月(如果需要,还可以创建另一个 3 个月 TTL),然后一次写入所有表(您可以根据需要缓冲对该表的写入)。另外,如果您的桌子有几个家庭,您可以将短命的家庭添加到同一张桌子上,但我更喜欢有不同的家庭(个人喜好)。

    如果答案是否定的,您仍然可以进行基于时间戳的范围扫描,以避免读取尽可能多的数据。如果(如您所说)该表将有 1 年的 TTL,您可以负担得起,这不像只需检索几天就必须对 30 年的数据进行全表扫描。

    顺便说一句,我建议您至少包含一个基于数字 uuid(模数、crc32、md5...)的 2-3 字节前缀,以便在区域之间获得均匀分布并更好地处理非活动 (或非常活跃的)用户。您无法预测用户的活跃程度。

    【讨论】:

    • 感谢@rmruano,保留重复数据绝对是我能想到的一个选项。但是,我仍然觉得这是 hack,因为我需要管理重复项。
    • 不客气。在 HBase 或任何其他 NoSQL 数据库中存在数据重复是很常见的,根本不是 hacky,因为我们不是在谈论 RDBM。您只需包装常见的 CRUD 操作即可写入两个表。作为您的情况,一个简单的用户位置日志可能只是添加另一个放置(缓冲),并且对于您所说的数亿用户而言,性能提升将是巨大的。无论如何,拥有更多桌子是您的选择,您只需在桌子上添加一些短命的家庭(1 周、1 个月、3 个月......)并进行基于家庭的扫描。
    猜你喜欢
    • 2014-07-05
    • 1970-01-01
    • 2015-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    • 2014-08-03
    • 1970-01-01
    相关资源
    最近更新 更多