2012-01-24 30 views
10

我有一个HBase架构设计相关的问题。问题很简单 - 我在hbase中存储“通知”,每个都有一个状态(“新”,“看到”和“读取”)。这里有API的,我需要提供:设计HBase架构以最好地支持特定的查询

  • 获取所有通知用户
  • 获取所有用户
  • “新”通知获取所有“新”通知的计数为用户
  • 对于通知
  • 更新状态
  • 所有用户的通知更新状态
  • 得到所有“新”的通知进行的跨数据库
  • 通知笑可以按照逆时间顺序扫描并允许分页。

我有一些想法,我想看看他们中的一个是否最好,或者我完全错过了一个好策略。所有这三个共同点,我认为每个通知有一行,并在rowkey中有用户ID是要走的路。为了获得分页的时间顺序,我需要在那里有一个相反的时间戳。我想将所有notif保存在一个表中(所以我不必为“为用户获取所有通知”而不必合并排序),也不想为辅助索引表编写批处理作业(因为更新了计数和状态应该是实时的)。

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

下一种可能性是(2)将状态编码到rowkey中,以便对“userId_reverseTimestamp_status”进行编码,然后对扫描执行rowkey正则表达式过滤。我看到的第一个问题是需要删除一行,并在状态更改时将通知数据复制到新行(推测每次通知应该只发生两次)。此外,由于状态是rowkey的最后一部分,对于每个用户,我们将扫描大量额外的行。这是一个很大的表现?最后,为了改变状态,我需要知道以前的状态是什么(构建行键),否则我需要做另一次扫描。 (3)有两个列族,一个用于静态notif数据,另一个作为状态标志,即“s:read”或“s:new”与s '作为cf和作为限定词的地位。每行只有一个,我可以对该cf做一个MultipleColumnPrefixFilter或SkipFilter w/ColumnPrefixFilter。在这里,我将不得不删除和创建状态更改列,但它应该比复制整行更轻量级。我唯一担心的是HBase书中的警告:HBase与“2个或3个以上的专栏系列”不太一致 - 可能如果系统需要扩展更多的查询功能,multi-cf策略将不会扩展。

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

+0

只有在从新到可能的单个转换过程中,通知才会显示'新'和'读'吗?这些通知的量是多少? – Gevorg

回答

2

你已经投入了很多思考,我认为所有三个都是合理的!

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

我认为你的问题的症结在于这种不断变化的状态部分。一般来说,像“读取” - >“删除” - >“重写”之类的东西引入了各种并发问题。如果你的任务失败了会发生什么?你的数据处于无效状态吗?你会删除一个记录吗?

我建议你将表格视为“仅附加”。基本上,按照你对#3的建议,但是不要去掉旗子,把它留在那里。如果读过某些东西,它可以有三个“s:看过”,“s:读过”(如果它是新的,我们可以认为它是空的)。你也可以看中并在三者中的每一个中加入时间戳,以显示该事件何时得到满足。由于所有操作都是只写和原子的,因此您不应该看到执行此操作时性能受到很大影响,因此您不必担心并发性。

我希望这是有帮助的。由于你的问题如此广泛,我不确定我是否回答了所有问题。请跟进另外的问题,我很乐意详细说明或讨论别的。

+0

Gppd关于使其成为只写的一点。不必破解原子更新使得它不那么复杂 - 我的过滤器只会是“只要没有未读状态”。 有人建议的另一种选择是每行有多个列,其中一行是用户的所有notif。据推测,这些列的排序方式与行相似。我的问题是,这是否给我们什么?他们还建议在notif上做一个ValueFilter(因此,状态存在于数据本身中,需要更新,而不是单独的CF)。我的猜测是这会有更糟糕的表现。思考? – dyross

1

我的解决办法是:

不要在HBase的保存通知状态(可见,新的)每个通知。通知使用简单的模式。键:userid_timestamp - 列:notification_message。

一旦客户端询问API“获取所有新通知”,保存时间戳(推送所有新通知)。关键:用户ID - colimn:All_new_notifications_pushed_time

与时间戳每个通知是不是“所有新的通知推送”假设“看到”下,如果更大的承担“新”

要获得所有新通知: 首先获得价值(timestamp),然后按用户ID 执行All_new_notifications_pushed_time的范围扫描,然后按键执行范围扫描notification_message列:从current_timestamp到All_new_notifications_pushed_time。

这将显着限制受影响的列,其中大多数应该在memstore中。

计算客户端上的新通知。