HBase 扫描很慢
HBase scans are slow
问题
我正在尝试使用 Phoenix 构建二级索引。索引创建需要几个小时。这似乎是由于 HBase 扫描速度慢,因为我注意到以下性能:
- 我可能需要 2 小时来扫描 table,而其他开发人员报告说扫描更大的 tables(1 亿行)需要几分钟。
- HBase shell 能够以大约 .每秒 10.000 的速率,这意味着需要 3800 秒(>1 小时!)来计算此 table.
的所有行
同时使用 HBase shell 和 Java 扫描器。
注意:GET(by rowkey) 操作以良好的性能实现(大约 0.5s)。
上下文
- 3800 万行/1000 列/单列系列/96Go,采用 GZ 压缩。
- 集群有 6 个节点(126Go RAM,24 核)和 5 个区域服务器。
- Hortonworks 数据平台 2.2.0
疑难解答
基于 HBase 书籍 (http://hbase.apache.org/book.html#performance),这是我已经检查过的内容:
1) 硬件
- IO(磁盘)
- NMon 表示磁盘的繁忙度从不超过 80%,最常见的是在 0 到 20% 之间
- Top 说 HBase JVM 没有交换(选中 2 个,共 5 个 RS)
- IO(network) : 每个节点的主动接口都在同一个交换机上(所有第二个被动接口都插在不同的交换机上)
2) JVM
- GC 暂停正常(每分钟左右暂停几毫秒)
- 堆看起来还不错(在极限附近没有达到峰值太久)
- CPU 出奇地低:从不超过 10%
- 话题 :
- 活动线程(10 "RpServe.reader=N" + 其他几个)显示没有争用
- 大量停放线程无所事事(60 "DefaultRpcServer.handler=n",大约 15 个其他)
- 大量没有任何线程状态的 IPC 客户端
3) 数据
- 使用 Hive + completebulkload 批量加载。
- 地区数量:
- 13 个区域意味着每个 RS 有 2 到 3 个大区域,这是预期的。
- 强制主要压缩后扫描性能保持不变。
- 区域大小相当均匀:11 个区域为 4,5Go (+/-0.5),2 个区域为 2,5Go
4) HBase 配置
大部分配置保持不变。
- HBase env 仅指示 JMX 控制台的端口
- HBase 站点对 Phoenix 的设置很少
一些我觉得还可以的参数
- hbase.hregion.memstore.block.multiplier
- hbase.hregion.memstore.flush.size : 134217728 字节 (134Go)
- Xmx 的 Xmn 比率:.2 Xmn 最大值:512 Mb Xms:6144m
- hbase.regionserver.global.memstore.lowerLimit : 0.38
- hbase.hstore.compactionTreshold : 3
- hfile.block.cache.size:0.4(块缓存大小占堆的百分比)
- 最大 HStoreFile (hbase.hregion.max.filesize):10 个 (10737418240)
- 客户端扫描器缓存:100 行 zookeeper 超时:30s
- 客户端最大键值大小:10mo
- hbase.regionserver.global.memstore.lowerLimit : 0.38
- hbase.regionserver.global.memstore.upperLimit : 0.40
- hstore 阻止存储文件:10
- hbase.hregion.memstore.mslab.enabled :
- 已启用 hbase.hregion.majorcompaction.jitter : 0.5
尝试了以下配置更改,对性能没有任何影响
- hbase-env.sh:试图增加 HBASE_HEAPSIZE=6144(因为它默认为 1000)
- hbase-site.xml :
- hbase.ipc.server.callqueue.read.ratio : 0.9
- hbase.ipc.server.callqueue.scan.ratio : 0.9
5) log say nothing usefull
cat hbase-hbase-master-cox.log | grep "2015-05-11.*错误"
cat hbase-hbase-regionserver-*.log | grep "2015-05-11.*错误"
什么都不打印
打印 WARN 显示不相关的错误
2015-05-11 17:11:10,544 警告 [B.DefaultRpcServer.handler=8,queue=2,port=60020] shortcircuit.ShortCircuitCache: ShortCircuitCache(0x2aca5fca): 无法加载 1074749724_BP-2077371184-184.10.17.65-1423758745093 由于 InvalidToken 异常。
2015-05-11 17:09:12,848 警告 [regionserver60020-smallCompactions-1430754386533] hbase.HBaseConfiguration: 配置选项 "hbase.regionserver.lease.period" 已弃用。相反,使用 "hbase.client.scanner.timeout.period"
在扫描时关闭块缓存(它正在搅动你的堆内存)
找出你的记录的大小,如果它 > 1 MB,请增加 hbase.scanner.timeout 句点 scan.setCacheBlocks(false);
scan.setCaching(x) x * 记录大小在一个短片中获取的内容,确保它接近 1 MB。
一些必要的检查:确保被扫描的 Tabled 区域在各个区域之间均匀分布。
(如果你已经完成批量加载 运行 一次主要压实)
明白了:关键是要将 "hot" 内容与 "cold" 内容分开到单独的列族中。列族用于将列存储在单独的 HFile 中,因此我们可以将一个列族用于索引(或经常读取)列,将另一个列族(即文件)用于所有其他列。
第一步:了解较小的列族扫描速度更快
我们只是丢弃冷内容来构建一个较小的列族(1655 列 -> 7 列)。
中等规模 table 扫描的表现:
- [37.876.602 行,1655 列] 扫描 1000 行耗时 39.4750
- [76.611.463行,7列]扫描1000行耗时1.8620
备注:
- 我们扫描前 1000 行时可以忽略总行数
- 从 Hbase 扫描时大行会产生开销 shell 在控制台中打印内容
第二步:生成多族HTable
我们通过从 Hive 生成 HFile 来进行批量加载。虽然文档说 we can't generate one multi family table,但可以单独生成 HFiles:
create table mytable_f1 (UUID string, source_col1, source_col2)
...
TBLPROPERTIES('hfile.family.path' = 'tmp/mytable/**f1**');
create table mytable_f1 (UUID string, source_col3, source_col4)
...
TBLPROPERTIES('hfile.family.path' = 'tmp/mytable/f2');
然后像往常一样简单地调用导入命令:
hadoop jar [hbase-server-jar] completebulkload /tmp/mytable mytable
问题
我正在尝试使用 Phoenix 构建二级索引。索引创建需要几个小时。这似乎是由于 HBase 扫描速度慢,因为我注意到以下性能:
- 我可能需要 2 小时来扫描 table,而其他开发人员报告说扫描更大的 tables(1 亿行)需要几分钟。
- HBase shell 能够以大约 .每秒 10.000 的速率,这意味着需要 3800 秒(>1 小时!)来计算此 table. 的所有行
同时使用 HBase shell 和 Java 扫描器。
注意:GET(by rowkey) 操作以良好的性能实现(大约 0.5s)。
上下文
- 3800 万行/1000 列/单列系列/96Go,采用 GZ 压缩。
- 集群有 6 个节点(126Go RAM,24 核)和 5 个区域服务器。
- Hortonworks 数据平台 2.2.0
疑难解答
基于 HBase 书籍 (http://hbase.apache.org/book.html#performance),这是我已经检查过的内容:
1) 硬件
- IO(磁盘)
- NMon 表示磁盘的繁忙度从不超过 80%,最常见的是在 0 到 20% 之间
- Top 说 HBase JVM 没有交换(选中 2 个,共 5 个 RS)
- IO(network) : 每个节点的主动接口都在同一个交换机上(所有第二个被动接口都插在不同的交换机上)
2) JVM
- GC 暂停正常(每分钟左右暂停几毫秒)
- 堆看起来还不错(在极限附近没有达到峰值太久)
- CPU 出奇地低:从不超过 10%
- 话题 :
- 活动线程(10 "RpServe.reader=N" + 其他几个)显示没有争用
- 大量停放线程无所事事(60 "DefaultRpcServer.handler=n",大约 15 个其他)
- 大量没有任何线程状态的 IPC 客户端
3) 数据
- 使用 Hive + completebulkload 批量加载。
- 地区数量:
- 13 个区域意味着每个 RS 有 2 到 3 个大区域,这是预期的。
- 强制主要压缩后扫描性能保持不变。
- 区域大小相当均匀:11 个区域为 4,5Go (+/-0.5),2 个区域为 2,5Go
4) HBase 配置
大部分配置保持不变。
- HBase env 仅指示 JMX 控制台的端口
- HBase 站点对 Phoenix 的设置很少
一些我觉得还可以的参数
- hbase.hregion.memstore.block.multiplier
- hbase.hregion.memstore.flush.size : 134217728 字节 (134Go)
- Xmx 的 Xmn 比率:.2 Xmn 最大值:512 Mb Xms:6144m
- hbase.regionserver.global.memstore.lowerLimit : 0.38
- hbase.hstore.compactionTreshold : 3
- hfile.block.cache.size:0.4(块缓存大小占堆的百分比)
- 最大 HStoreFile (hbase.hregion.max.filesize):10 个 (10737418240)
- 客户端扫描器缓存:100 行 zookeeper 超时:30s
- 客户端最大键值大小:10mo
- hbase.regionserver.global.memstore.lowerLimit : 0.38
- hbase.regionserver.global.memstore.upperLimit : 0.40
- hstore 阻止存储文件:10
- hbase.hregion.memstore.mslab.enabled :
- 已启用 hbase.hregion.majorcompaction.jitter : 0.5
尝试了以下配置更改,对性能没有任何影响
- hbase-env.sh:试图增加 HBASE_HEAPSIZE=6144(因为它默认为 1000)
- hbase-site.xml :
- hbase.ipc.server.callqueue.read.ratio : 0.9
- hbase.ipc.server.callqueue.scan.ratio : 0.9
5) log say nothing usefull
cat hbase-hbase-master-cox.log | grep "2015-05-11.*错误"
cat hbase-hbase-regionserver-*.log | grep "2015-05-11.*错误"
什么都不打印
打印 WARN 显示不相关的错误
2015-05-11 17:11:10,544 警告 [B.DefaultRpcServer.handler=8,queue=2,port=60020] shortcircuit.ShortCircuitCache: ShortCircuitCache(0x2aca5fca): 无法加载 1074749724_BP-2077371184-184.10.17.65-1423758745093 由于 InvalidToken 异常。
2015-05-11 17:09:12,848 警告 [regionserver60020-smallCompactions-1430754386533] hbase.HBaseConfiguration: 配置选项 "hbase.regionserver.lease.period" 已弃用。相反,使用 "hbase.client.scanner.timeout.period"
在扫描时关闭块缓存(它正在搅动你的堆内存)
找出你的记录的大小,如果它 > 1 MB,请增加 hbase.scanner.timeout 句点 scan.setCacheBlocks(false);
scan.setCaching(x) x * 记录大小在一个短片中获取的内容,确保它接近 1 MB。
一些必要的检查:确保被扫描的 Tabled 区域在各个区域之间均匀分布。
(如果你已经完成批量加载 运行 一次主要压实)
明白了:关键是要将 "hot" 内容与 "cold" 内容分开到单独的列族中。列族用于将列存储在单独的 HFile 中,因此我们可以将一个列族用于索引(或经常读取)列,将另一个列族(即文件)用于所有其他列。
第一步:了解较小的列族扫描速度更快
我们只是丢弃冷内容来构建一个较小的列族(1655 列 -> 7 列)。
中等规模 table 扫描的表现:
- [37.876.602 行,1655 列] 扫描 1000 行耗时 39.4750
- [76.611.463行,7列]扫描1000行耗时1.8620
备注:
- 我们扫描前 1000 行时可以忽略总行数
- 从 Hbase 扫描时大行会产生开销 shell 在控制台中打印内容
第二步:生成多族HTable
我们通过从 Hive 生成 HFile 来进行批量加载。虽然文档说 we can't generate one multi family table,但可以单独生成 HFiles:
create table mytable_f1 (UUID string, source_col1, source_col2)
...
TBLPROPERTIES('hfile.family.path' = 'tmp/mytable/**f1**');
create table mytable_f1 (UUID string, source_col3, source_col4)
...
TBLPROPERTIES('hfile.family.path' = 'tmp/mytable/f2');
然后像往常一样简单地调用导入命令:
hadoop jar [hbase-server-jar] completebulkload /tmp/mytable mytable