如何在毫秒内从HBase table查询数据?
How can I query data from HBase table in millisecond?
我正在写一个从Hbase查询分页数据的接口table,我通过一些条件查询分页数据,但是它很慢。我的rowkey
是这样的:12345678:yyyy-mm-dd
,长度为8个随机数和日期。我尝试使用Redis缓存所有rowkeys
并在其中进行分页,但很难通过其他条件查询数据。
我也考虑在Hbase中设计二级索引,和同事讨论过,他们认为二级索引很难维护。
那么,谁能给我出出主意呢?
在 Hbase 中,为了获得良好的读取性能,您希望通过少量获取(请求单行)或小型扫描(请求超过行范围)来检索数据。 Hbase 按键存储您的数据,因此最重要的想法是提出允许它的行键。
您的密钥似乎只包含随机整数和日期,因此我假设您的查询是关于对标有时间的记录进行分页的。
第一个想法是,在典型的分页场景中,您一次只能访问一页,然后从第 1 页导航到第 2 页再到第 3 页等。如果您想对日期 2015-08-16 的所有记录进行分页,您可以使用开始键 '\0:2015-08-16'(因为它小于 2015-08-16 中的任何行)扫描 50 行来检索第一页。检索第一页后,您将获得第一页的最后一个键,例如“12345:2015-08-16”。您可以使用它(或 12346:2015-08-16)使用 50 行的开始键 12346:2015-08-16 进行另一次扫描以检索第 2 页,依此类推。因此,使用这种方法,您可以像使用预定义返回行数的单次扫描一样快速查询您的页面。所以你可以使用 last page row key 作为 paging API 的参数,或者只是将 last row key 放在 redis 中,这样下一次 paging API 调用就会在那里找到它。
在某些用户进入并直接单击第 100 页之前,所有这一切都非常有效。或者尝试在他在第 2 页时单击第 5 页。在这种情况下,您可以使用类似的 nSkippedPages * 50 行扫描。这不会像顺序访问一样快,但它不是通常的页面使用模式。然后,您可以使用 redis 将页面结果的最后一行缓存在类似 pageNumber -> rowKey 的结构中。然后,如果下一个用户来点击第 100 页,它将看到与通常点击页面 1-点击页面 2-点击页面 3 场景相同的性能。
然后为了让第一次点击第 99 页的用户更快,您可以编写一个单独的守护进程,它每 50 行检索一次并将结果作为页面索引放入 redis。然后每 10-15 分钟启动一次,并说您的页面索引最多有 10-15 分钟的陈旧数据。
您还可以设计一个单独的 API 预加载大量 N 页面的行键(比如大约 100 页,它可以是异步的,例如不要等待实际预加载完成)。它所做的只是使用 KeyOnlyFilter 和 50*N 结果进行扫描,然后为每个页面选择行键。因此它接受 rowkey 并使用 N 页的 rowkey 缓存填充 redis。然后,当用户进入第一页时,您会为他获取前 100 页的行键,因此当他点击页面上看到的某个页面 link 时,页面起始行键将可用。使用合适的预加载批量大小,您可以接近所需的延迟。
可以使用 Scan.setMaxResults() 或 PageFilter 来实现限制。
"skip nPages * 50 rows" 尤其是 "output every 50th row" 功能似乎更棘手,例如对于后者,您可能最终会执行全扫描以检索密钥或编写 map-reduce 来执行此操作,首先,不清楚如何在不通过网络发送行的情况下执行此操作,因为请求可以分布在多个区域。
如果您正在寻找在 HBase 中维护的二级索引,有几个开源选项(Splice Machine、Lilly 等)。您可以在几毫秒内完成索引查找。
首先,如果使用大数据进行扩展,AFAIK 随机数 + 行键的日期模式可能会导致热点。
关于分页:
如果您使用 cloudera
,我会提供 solr
+ hbase
,然后是 cloudera search
。它提供了良好的性能(在我们的案例中得到证明),同时每页查询 100 次,并且通过网络服务调用我们已经填充了 angularjs
仪表板。
另外,最重要的是你可以在页面之间来回移动没有任何问题..
下图描述了这一点。
为此,您需要创建集合(从 hbase 数据)并可以使用 solrj api
单独使用 Hbase 和扫描 api 不适用于快速查询。
除此之外,请看我的回答。哪个对实现细节更有洞察力...
How to achieve pagination in HBase?
Hbase only 解决方案可以是 Hindex(基于协处理器的解决方案)
Link解释更详细
Hindex架构:
我正在写一个从Hbase查询分页数据的接口table,我通过一些条件查询分页数据,但是它很慢。我的rowkey
是这样的:12345678:yyyy-mm-dd
,长度为8个随机数和日期。我尝试使用Redis缓存所有rowkeys
并在其中进行分页,但很难通过其他条件查询数据。
我也考虑在Hbase中设计二级索引,和同事讨论过,他们认为二级索引很难维护。
那么,谁能给我出出主意呢?
在 Hbase 中,为了获得良好的读取性能,您希望通过少量获取(请求单行)或小型扫描(请求超过行范围)来检索数据。 Hbase 按键存储您的数据,因此最重要的想法是提出允许它的行键。 您的密钥似乎只包含随机整数和日期,因此我假设您的查询是关于对标有时间的记录进行分页的。
第一个想法是,在典型的分页场景中,您一次只能访问一页,然后从第 1 页导航到第 2 页再到第 3 页等。如果您想对日期 2015-08-16 的所有记录进行分页,您可以使用开始键 '\0:2015-08-16'(因为它小于 2015-08-16 中的任何行)扫描 50 行来检索第一页。检索第一页后,您将获得第一页的最后一个键,例如“12345:2015-08-16”。您可以使用它(或 12346:2015-08-16)使用 50 行的开始键 12346:2015-08-16 进行另一次扫描以检索第 2 页,依此类推。因此,使用这种方法,您可以像使用预定义返回行数的单次扫描一样快速查询您的页面。所以你可以使用 last page row key 作为 paging API 的参数,或者只是将 last row key 放在 redis 中,这样下一次 paging API 调用就会在那里找到它。
在某些用户进入并直接单击第 100 页之前,所有这一切都非常有效。或者尝试在他在第 2 页时单击第 5 页。在这种情况下,您可以使用类似的 nSkippedPages * 50 行扫描。这不会像顺序访问一样快,但它不是通常的页面使用模式。然后,您可以使用 redis 将页面结果的最后一行缓存在类似 pageNumber -> rowKey 的结构中。然后,如果下一个用户来点击第 100 页,它将看到与通常点击页面 1-点击页面 2-点击页面 3 场景相同的性能。
然后为了让第一次点击第 99 页的用户更快,您可以编写一个单独的守护进程,它每 50 行检索一次并将结果作为页面索引放入 redis。然后每 10-15 分钟启动一次,并说您的页面索引最多有 10-15 分钟的陈旧数据。
您还可以设计一个单独的 API 预加载大量 N 页面的行键(比如大约 100 页,它可以是异步的,例如不要等待实际预加载完成)。它所做的只是使用 KeyOnlyFilter 和 50*N 结果进行扫描,然后为每个页面选择行键。因此它接受 rowkey 并使用 N 页的 rowkey 缓存填充 redis。然后,当用户进入第一页时,您会为他获取前 100 页的行键,因此当他点击页面上看到的某个页面 link 时,页面起始行键将可用。使用合适的预加载批量大小,您可以接近所需的延迟。
可以使用 Scan.setMaxResults() 或 PageFilter 来实现限制。 "skip nPages * 50 rows" 尤其是 "output every 50th row" 功能似乎更棘手,例如对于后者,您可能最终会执行全扫描以检索密钥或编写 map-reduce 来执行此操作,首先,不清楚如何在不通过网络发送行的情况下执行此操作,因为请求可以分布在多个区域。
如果您正在寻找在 HBase 中维护的二级索引,有几个开源选项(Splice Machine、Lilly 等)。您可以在几毫秒内完成索引查找。
首先,如果使用大数据进行扩展,AFAIK 随机数 + 行键的日期模式可能会导致热点。
关于分页:
如果您使用 cloudera
,我会提供 solr
+ hbase
,然后是 cloudera search
。它提供了良好的性能(在我们的案例中得到证明),同时每页查询 100 次,并且通过网络服务调用我们已经填充了 angularjs
仪表板。
另外,最重要的是你可以在页面之间来回移动没有任何问题..
下图描述了这一点。
为此,您需要创建集合(从 hbase 数据)并可以使用 solrj api
单独使用 Hbase 和扫描 api 不适用于快速查询。
除此之外,请看我的回答。哪个对实现细节更有洞察力...
How to achieve pagination in HBase?
Hbase only 解决方案可以是 Hindex(基于协处理器的解决方案)
Link解释更详细