设计HBase架构以最好地支持特定查询

时间:2012-01-24 07:45:40

标签: java hadoop nosql hbase

我有一个与HBase架构设计相关的问题。问题很简单 - 我在hbase中存储“通知”,每个都有一个状态(“new”,“see”和“read”)。以下是我需要提供的API:

  • 获取用户的所有通知
  • 获取用户的所有“新”通知
  • 获取用户的所有“新”通知的计数
  • 更新通知的状态
  • 更新所有用户通知的状态
  • 获取数据库中的所有“新”通知
  • 通知应按相反的时间顺序扫描,并允许分页。

我有一些想法,我想看看其中一个是否最好,或者我是否完全错过了一个好的策略。这三种情况相同,我认为每个通知都有一行,并且在rowkey中有用户ID是要走的路。为了按时间顺序排列分页,我需要在那里有一个反向时间戳。我想将所有notifs保存在一个表中(因此我不必为“为用户调用所有notificatiosn”调用合并排序)并且不想为二级索引表编写批处理作业(因为更新到计数和状态应该是实时的。)

最简单的方法是(1)行键是“userId_reverseTimestamp”并对客户端的状态进行过滤。这似乎很幼稚,因为我们将通过网络发送大量不必要的数据。

下一种可能性是(2)将状态编码到rowkey中,因此要么“userId_reverseTimestamp_status”,要么对扫描进行rowkey正则表达式过滤。我看到的第一个问题是需要删除行并在状态更改时将通知数据复制到新行(可能每个通知应该发生两次)。此外,由于状态是rowkey的最后一部分,因此对于每个用户,我们将扫描许多额外的行。这是一个重大的表现吗?最后,为了更改状态,我需要知道以前的状态是什么(构建行键),否则我将需要进行另一次扫描。

我的最后一个想法是(3)有两个列族,一个用于静态notif数据,一个用作状态的标志,即“s:read”或“s:new”with s'作为cf和作为限定符的状态。每行只有一个,我可以针对该cf执行MultipleColumnPrefixFilter或SkipFilter w / ColumnPrefixFilter。在这里,我将不得不删除并创建状态更改列,但它应该比复制整行更轻量级。我唯一担心的是HBase书中警告说HBase不能很好地处理“超过2或3列系列” - 也许如果系统需要扩展具有更多的查询功能,那么多cf策略将无法扩展

所以(1)似乎会有太多的网络开销。 (2)似乎浪费了复制数据所花费的成本和(3)可能导致太多家庭的问题。在(2)和(3)之间,哪种类型的滤波器应该提供更好的性能?在这两种情况下,扫描都会查看用户的每一行,这可能主要是读取通知 - 这会有更好的性能。我想我倾向于(3) - 还有其他选择(或调整)我错过了吗?

2 个答案:

答案 0 :(得分:2)

你已经考虑了很多,我认为这三个都是合理的!

您希望主键是与时间戳连接的用户名,因为您的大多数查询都是“按用户”。这将有助于轻松分页扫描,并可以非常快速地获取用户信息。

我认为你问题的关键在于这个不断变化的状态部分。一般来说,像“阅读” - > “删除” - > “重写”引入了各种并发问题。如果您的任务失败,会发生什么?您是否有无效状态的数据?你会丢掉一张唱片吗?

我建议您将表视为“仅附加”。基本上,做你对#3的建议,但不要删除标志,保持在那里。如果已读取某些内容,则可以在其中显示三个“s:seen”,“s:read”(如果它是新的,我们可以假设它是空的)。你也可以想象并在三者中的每一个中加上时间戳来显示该事件何时满足。你不应该看到这样做的性能损失,然后你不必担心并发性,因为所有操作都是只写和原子的。

我希望这会有所帮助。因为你的问题太广泛,我不确定我是否回答了所有问题。请跟进补充问题,我很乐意详细说明或讨论其他问题。

答案 1 :(得分:1)

我的解决方案是:

不要在hbase中为每个通知保存通知状态(可见,新)。对于通知,请使用简单模式。密钥:userid_timestamp - 列:notification_message。

客户端询问API“获取所有新通知”后,保存时间戳(推送所有新通知)。密钥:userid - colimn:All_new_notifications_pushed_time

每个带有时间戳的通知都低于“所有推送的新通知”假定为“已见过”,如果更大则通知为“新”

要获取所有新通知: 首先通过userid获取All_new_notifications_pushed_time的值(时间戳) 然后按键在notification_message列上执行范围扫描:从current_timestamp到All_new_notifications_pushed_time。

这将显着限制受影响的列,其中大部分应位于memstore中。

在客户端上计算新通知。