codecamp

从HBase读取

从HBase读取

如果您遇到性能问题,邮件列表可以提供帮助。例如,这里有一个关于解决读取时间问题的一个很好的通用线程:HBase随机读取延迟> 100ms

扫描缓存

例如,如果将HBase用作MapReduce作业的输入源,请确保MapReduce作业的输入扫描实例已经将setCaching设置为大于默认值(即1)的值。使用默认值意味着map-task将为处理的每个记录回调region-server。例如,将此值设置为500将一次传输500行到要处理的客户端。缓存值很大是有成本/收益的,因为客户端和RegionServer的内存成本更高,因此更大并不总是更好。

在MapReduce作业中扫描缓存

MapReduce作业中的扫描设置值得特别注意。如果在客户端返回到RegionServer以获取下一组数据之前处理一批记录需要更长时间,则可能会在Map任务中导致超时(例如,UnknownScannerException)。发生此问题的原因是每行发生重要的处理。如果快速处理行,请将缓存设置得更高。如果您更慢地处理行(例如,每行进行大量转换,写入),则将缓存设置为更低。

超时也可能发生在非MapReduce用例中(即,执行扫描的单线程HBase客户端),但通常在MapReduce作业中执行的处理往往会加剧此问题。

扫描属性选择

每当使用扫描处理大量行(特别是用作MapReduce源)时,请注意选择了哪些属性。如果scan.addFamily调用,则指定ColumnFamily中的所有属性将返回给客户端。如果只处理少量可用属性,则只应在输入扫描中指定那些属性,因为属性过度选择对大型数据集而言是一个非常重要的性能损失。

避免扫描查找

当使用scan.addColumn明确选择列时,HBase将调度查找操作以在所选列之间进行查找。当行包含少量列且每列只有几个版本时,这可能是效率低下。 如果不查找至少超过5-10个列/版本或512-1024字节,则查找操作通常会比较慢。

为了机会性地向前看几列/版本以查看在调度查找操作之前是否可以找到下一列/版本,可以在Scan对象上设置新属性Scan.HINT_LOOKAHEAD。以下代码指示RegionServer在调度查找之前尝试以下两次迭代:

Scan scan = new Scan();
scan.addColumn(...);
scan.setAttribute(Scan.HINT_LOOKAHEAD, Bytes.toBytes(2));
table.getScanner(scan);

关闭ResultScanners

这不仅仅是提高性能,而是避免性能问题。如果忘记关闭ResultScanners,可能会导致RegionServers出现问题。始终将ResultScanner处理包含在try/catch块中。

Scan scan = new Scan();
// set attrs...
ResultScanner rs = table.getScanner(scan);
try {
  for (Result r = rs.next(); r != null; r = rs.next()) {
  // process result...
} finally {
  rs.close();  // always close the ResultScanner!
}
table.close();

块缓存

可以通过该setCacheBlocks方法将扫描实例设置为使用RegionServer中的块缓存。对于输入扫描到MapReduce作业,这应该是false。对于频繁访问的行,建议使用块缓存。

通过在堆外移动块缓存来缓存更多数据。请参阅堆外块缓存

行键的最佳加载

执行只需要行键的表扫描(没有族,限定符,值或时间戳)时,请使用setFilter向扫描仪添加带有MUST_PASS_ALL运算符的FilterList。筛选器列表应包括FirstKeyOnlyFilter和KeyOnlyFilter。使用此筛选器组合将导致最坏的情况,即RegionServer从磁盘读取单个值,并为单个行将最小的网络流量发送到客户端。

并发:监控数据传播

执行大量并发读取时,监视目标表的数据传播。如果目标表具有的区域太少,则可能从太少的节点提供读取。

请参阅表创建:预创建区域以及HBase配置

Bloom过滤器

启用Bloom过滤器可以节省您的磁盘空间,并有助于改善读取延迟。

Bloom过滤器是在HBase-1200 Add bloomfilters中开发的。这里描述的Bloom过滤器实际上是HBase中的第二版。在0.19.x版本中,HBase根据欧盟委员会一个实验室项目034819所做的工作提供了动态bloom选项。HBase bloom工作的核心后来被引入Hadoop以实现org.apache.hadoop.io.BloomMapFile。

Bloom StoreFile足迹

Bloom过滤器向StoreFile常规FileInfo数据结构添加项,然后向StoreFile元数据部分添加两个额外项。

BloomFilter在StoreFile``FileInfo数据结构中:

FileInfo有一个BLOOM_FILTER_TYPE条目,它设置为NONE,ROW或ROWCOL.

StoreFile元数据中的BloomFilter条目:

BLOOM_FILTER_META保持Bloom Size,使用Hash函数等。它的大小很小,并且在StoreFile.Reader加载时缓存。

BLOOM_FILTER_DATA是实际的bloomfilter数据,按需获得。如果已启用(默认情况下已启用),存储在LRU缓存中。

Bloom过滤器配置

io.storefile.bloom.enabled 全局关闭开关:

io.storefile.bloom.enabled在Configuration用作关闭l开关,防止出现问题;Default= true。

io.storefile.bloom.error.rate:

io.storefile.bloom.error.rate=平均误报率。Default= 1%。

io.storefile.bloom.max.fold:

io.storefile.bloom.max.fold=保证最低折叠率,大多数人都不应该管它。Default= 7,或者至少可以折叠到原始大小的1/128。=

Hedged读取

Hedged读取是HDFS的一项功能,在Hadoop 2.4.0中引入了HDFS-5776。通常,为每个读取请求生成一个线程。但是,如果启用了Hedged读取,则客户端会等待一段可配置的时间,如果读取未返回,则客户端会针对相同数据的不同块副本生成第二个读取请求。使用先返回的一个,并丢弃另一个读取请求。

在启用Hedged读取的情况下运行时要记住的其他问题包括:

  • 它们可能导致网络拥塞。见HBASE-17083
  • 确保将线程池设置得足够大,以便池上的阻塞不会成为瓶颈(再次参见HBASE-17083

由于HBase RegionServer是HDFS客户端,因此您可以在HBase中启用Hedged读取,方法是将以下属性添加到R​​egionServer的hbase-site.xml并调整值以适合您的环境。

Hedged读取的配置

  • dfs.client.hedged.read.threadpool.size - 专用于服务Hedged读取的线程数。如果将其设置为0(默认值),则禁用Hedged读取。
  • dfs.client.hedged.read.threshold.millis - 产生第二个读取线程之前等待的毫秒数。

Hedged读取配置示例:

<property>
  <name>dfs.client.hedged.read.threadpool.size</name>
  <value>20</value>  <!-- 20 threads -->
</property>
<property>
  <name>dfs.client.hedged.read.threshold.millis</name>
  <value>10</value>  <!-- 10 milliseconds -->
</property>

使用以下指标调整群集上Hedged读取的设置。

Hedged读取的指标:

  • hedgedReadOps - 已触发Hedged读取线程的次数。这可能表明读取请求通常很慢,或者Hedged读取的触发太快。
  • hedgeReadOpsWin - Hedged读取线程比原始线程快的次数。这可能表示给定的RegionServer在处理请求时遇到问题。
HBase相关内容
从HBase删除
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

HBase快速入门

HBase批量加载

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }