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

dyr*_*oss 10 java hadoop hbase nosql

我有一个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",带有's'作为cf以及作为限定符的状态.每行只有一个,我可以针对该cf执行MultipleColumnPrefixFilter或SkipFilter w/ColumnPrefixFilter.在这里,我将不得不删除并创建状态更改列,但它应该比复制整行更轻量级.我唯一担心的是HBase书中警告说HBase不能很好地处理"超过2或3列系列" - 也许如果系统需要扩展具有更多的查询功能,那么多cf策略将无法扩展.

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

Don*_*ner 2

您考虑了很多,我认为这三个都是有道理的!

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

我认为你问题的症结在于状态的改变。一般来说,“读取”->“删除”->“重写”之类的操作会引入各种并发问题。如果您的任务在此期间失败会发生什么?您是否有处于无效状态的数据?你会打破记录吗?

我建议您将该表视为“仅附加”。基本上,按照您对 #3 的建议进行操作,但不要删除该标志,而是将其保留在那里。如果某些内容已被读取,它可以有三个“s:seen”、“s:read”(如果它是新的,我们可以假设它是空的)。您还可以在这三个事件中分别添加一个时间戳,以显示该事件何时得到满足。这样做不会对性能造成太大影响,而且您不必担心并发性,因为所有操作都是只写和原子的。

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