- 浏览: 359552 次
文章分类
最新评论
-
jfeifjlafekae:
另外,为什么存储日志会有拆分过程,而不是rotation方式? ...
HBASE数据架构 -
jfeifjlafekae:
“当然,数据刷写时,一个Region只要有一个列族的memSt ...
HBASE数据架构 -
hmc52107521:
你好,params.keys,params.values以及# ...
mybatis中使用map类型参数,其中key为列名,value为列值 -
zhangxiong0301:
qindongliang1922 写道AM中其它与内存相关的参 ...
(转)YARN内存配置 -
qindongliang1922:
AM中其它与内存相关的参数,还有JVM相关的参数,这些参数可以 ...
(转)YARN内存配置
<name>hbase.regionserver.handler.count</name> <value>40</value> </property>? ? ? ?hbase.regionserver.handler.count属性可控制RPC侦听程序的线程数。该属性的默认值为10。这是一个相当低的值,这样设置的目的是防止RegionServer在某些情况下出现耗尽内存的情况。
? ? ? ?如果RegionServer上的可用内存较少,就应该将该属性设为一个较低的值。较低的值也适用于需要大量内存才能对请求进行处理的情形(比如将大值写入HBase或在大型缓存中扫描数据)。将hbase.regionserver.handler.count属性设为较高值意味着可以有更多的并发客户端,这可能会消耗掉很多RegionServer的内存,甚至有可能会用光所有的内存。
? ? ? ?如果每个请求只需要一点点内存,但每秒的交易次数(TPS)却很高,那么就应该将该属性设为一个较大的值,以使RegionServer可以处理更多的并发请求。
? ? ? ?在调整该属性的同时,建议启用RPC级的日志记录功能,然后监控每个RPC请求的内存使用情况和GC状态。
?
三、使用自定义算法预创建区域
? ? ? ?当我们在HBase中创建一张表时,该表一开始只有一个区域。插入该表的所有数据会保存在这个区域中。随着数据的不断增加,当该区域的大小达到一定阀值时,就会发生区域分割(Region Splitting)。这个区域会分成两半,以便使该表可以处理更多的数据。
? ? ? ?在写密集的HBase集群中,区域分割会带来以下几个需要解决的问题。
? ? ? ?分割/合并风暴问题。
? ? ? ?如果数据均匀地增长,大部分区域就会在同一时间发生分割,从而导致大量的磁盘I/O和网络流量。
? ? ? ?只有在分割出了足够多个区域之后,负载才会均衡。
? ? ? ?尤其是在表刚创建时,所有请求都会发给首个区域所在的那台RegionServer。
? ? ? ?对于第一个问题,可以参考“HBase基本性能调整”的“管理区域分割”一节,可通过手动分割的方法来解决。
? ? ? ?对于第二个问题,可以参考“在数据移入HBase前预创建区域”一节,可通过在创建表时预先创建好一些区域的方法来避免这一问题。使用HBase的RegionSplitter工具来预创建区域的方法。
? ? ? ?在默认情况下,RegionSplitter实用工具会使用MD5算法来生成MD5校验和,以此来作为区域的开始键。键值的范围是“00000000”到“7FFFFFFF”。这种算法(HexStringSplit)适用于很多情况,但在有些情况下,你可能更需要使用一种自己的算法来生成键值,以使负载能在集群中分散开来。
? ? ? ?HBase的行键完全由向HBase写入数据的应用程序所控制,在很多情况下,(由于这样或那样的原因)行键的范围和分布情况是可以预测的。因此,可以先计算出各区域的分割键,然后再使用这些分割键来创建预分割区域。
? ? ? ?我们将使用一组记录在文本文件中的区域开始键来创建表的预定义区域。
? ? ? ?1.创建一个split-keys文件。在该文件中输入一组区域分割键,每个键一行。假设该文件包含有如下一些开始键:
$ cat split-keysa0000affffb0000bffff
? ? ? ?2.创建Java类FileSplit,用它来实现org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm接口。
import org.apache.hadoop.hbase.util.Bytes;import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm;public class FileSplit implements SplitAlgorithm {//public static final String SPLIT_KEY_FILE = "split-keys";private String splitKeyFile;public FileSplit (String splitKeyFile) {this.splitKeyFile = splitKeyFile;}@Overridepublic byte[] split(byte[] start, byte[] end) {return null;}@Overridepublic byte[][] split(int numberOfSplits) {BufferedReader reader=null;try {List<byte[]> regions = new ArrayList<byte[]>();//一行一行读reader = new BufferedReader(new FileReader(splitKeyFile));String line;while ((line = reader.readLine()) != null) {//System.out.println(line);if (line.trim().length() > 0) {regions.add(Bytes.toBytes(line));}}return regions.toArray(new byte[0][]);} catch (IOException e) {throw new RuntimeException("Error reading splitting keys from " + splitKeyFile, e);} catch (Exception e) {e.printStackTrace();} finally {try {if (reader != null) reader.close();} catch (IOException e) {e.printStackTrace();}}return null;}@Overridepublic byte[] firstRow() {return null;}@Overridepublic byte[] lastRow() {return null;}@Overridepublic byte[] strToRow(String input) {return null;}@Overridepublic String rowToStr(byte[] row) {return null;}@Overridepublic String separator() {return null;}}
? ? ? ?3.编译该Java文件。
$ javac -classpath $HBASE_HOME/hbase-0.92.0.jar FileSplit.java
? ? ? ?4.将包含有分割键信息的split-keys文件复制到编译生成FileSplit类的目录下。
? ? ? ?5.运行如下脚本来在创建表的时候预创建一些区域。
$ export HBASE_CLASSPATH=$HBASE_CLASSPATH:./$ $HBASE_HOME/bin/hbase org.apache.hadoop.hbase.util.RegionSplitter -D split.algorithm=FileSplit -c 2 -f f1 test_table
? ? ? ?6.通过HBase的Web用户界面确认表和预定义区域是否已正确创建。
? ? ? ?HBase带有一个名为RegionSplitter的实用工具,该类可以用于:
? ? ? ?创建带预分割区域的HBase表? ? ? ?对现有的表中的所有区域进行滚动分割? ? ? ?使用自定义算法来分割区域
? ? ? ?为了能在创建表时分割区域,只需要像第2步那样实现一下split()方法。RegionSplitter类会调用该方法来对整张表进行分割。在我们的实现中,该方法会从我们准备好的文件中读取分割键(每个键一行),然后将它们转换并保存在一个存储该表所有初始区域的分割键的byte[]数组中。
? ? ? ?为了能使用该类来分割区域,我们将FileSplit类加入到了HBASE_CLASSPATH中,然后以带如下参数的方式调用了RegionSplitter实用程序。
? ? ? ?-D split.algorithm=FileSplit:指定分割算法。? ? ? ?-c 2:表分割的区域数。在本实现中没有用到。? ? ? ?-f f1:创建一个名为“f1”的列族。? ? ? ?test_table:待创建的表的名称。
? ? ? ?正如你在第6步中看到那样,我们用4个分割键将test_table分成了5个区域。这4个分割键正是我们写在split-keys文件中的内容。
? ? ? ?该表的其他属性都使用了默认值,你可以在HBase Shell中使用alter命令来修改其中的一些属性。
? ? ? ?请注意,即便是在对区域进行过分割之后,也仍然需要在应用层对行键进行设计,以避免将过多连续的行键写入同一个区域。你需要仔细地选择,找到一种适合你的数据访问模式的分割算法。
? ? ? ?该方法的另一个适用场景是用来提高将HBase表导出备份的数据导入回HBase的速度。
? ? ? ?你可以使用一个简单的脚本来备份各区域的开始键。有了FileSplit类,我们可以使用原来的这些键来恢复HBase表的区域边界,然后再以使用导出数据文件进行导入的方式来恢复数据。
? ? ? ?与将数据导入到同一个区域相比,这种方法能够显著提高数据恢复的速度,因为它会提前在多台RegionServer上恢复好多个区域,并且让这些区域均衡分布在多台RegionServer上。
?
四、避免写密集集群中的更新阻塞
? ? ? ?在写密集的HBase集群中,你可能会发现有写入速度不稳定的现象。大多数写操作都非常快,但有些写操作却非常慢。对于一个在线系统来说,无论平均速度如何,这种写入速度的不稳定都是不可接受的。
? ? ? ?导致这种情况的原因可能有两个:
? ? ? ?分割/合并使得集群的负荷非常高? ? ? ?更新操作被RegionServer给阻塞住了
? ? ? ?正如我们在“HBase基本性能调整”中描述的那样,你可以通过“禁用自动分割/合并,然后在低负载时手动进行分割/合并”的方式来避免分割/合并问题。
? ? ? ?要在RegionServer日志中进行一下查找,如果发现很多带“Blocking updates for ...”字样的消息,说明很可能就有很多更新都被阻塞住了,这样的更新操作的响应时间可能就是非常差。
? ? ? ?若要解决这类问题,必须同时对服务器端和客户端的配置作出调整,才能获得稳定的写入速度。
vi $HBASE_HOME/conf/hbase-site.xml <property> <name>hbase.hregion.memstore.block.multiplier</name> <value>8</value> </property><property><name>hbase.hstore.blockingStoreFiles</name><value>20</value></property>
? ? ? ?HBase写入操作的工作流程。
? ? ? ?数据的修改首先会被写入到了RegionServer的HLog(WAL预写日志)中,以此方式来持久化在HDFS中。然后,该修改被传给了宿主HRegion,然后传入到其所属列族的HStore的内存空间里(即MemStore)。当MemStore的大小达到一定阀值时,数据修改会被写入到HDFS上的StoreFile中。StoreFiles在内部使用HFile文件格式来存储数据。
? ? ? ?HBase是一种多版本并发控制(MVCC,Multiversion Concurrency Control)的架构。在更新/删除任何旧数据时,HBase都不会进行覆盖,而是给数据增加一个新版本。这使得HBase的写速度非常快,因为所有写操作都是顺序化的操作。
? ? ? ?如果HDFS上的小StoreFile太多,HBase就会启动合并操作来将它们重写为几个大一些的StoreFile,同时减少StoreFile文件的数量。当一个区域的大小达到一定阀值时,它又会被分成两个部分。
? ? ? ?为了防止合并/分割的时间过长并导致内存耗尽的错误,在某一区域的MemStore的大小达到一定阀值时,HBase会对更新进行阻塞。该阀值的定义为:
? ? ? ?hbase.hregion.memstore.flush.size 乘以?hbase.hregion.memstore.block.multiplier
? ? ? ?hbase.hregion.memstore.flush.size属性指定了MemStore在大小达到何值时会被写入到磁盘中。其默认值是128MB(0.90版本是64MB)。
? ? ? ?hbase.hregion.memstore.block.multiplier属性的默认值是2,这意味着,如果MemStore的大小达到了256MB(128 * 2),该区域上的更新将被阻塞。对于写密集集群的更新高峰期来说,这个值太小了,所以我们要调高该阻塞阀值。
? ? ? ?我们通常会让hbase.hregion.memstore.flush.size属性保持为默认值,然后将hbase.hregion.memstore.block.multiplier属性调整为一个较大的值(比如8),以此来提高MemStore阻塞阀值,减少更新阻塞发生的次数。
? ? ? ?请注意,调高hbase.hregion.memstore.block.multiplier会增大写盘时出现合并/分割问题的可能性,所以调整时一定要小心。
? ? ? ?第2步适用于另一种阻塞情况。如果任何一个Store的StoreFiles数(每个写盘MemStore一个StoreFile)超过了hbase.hstore.blockingStoreFiles(默认为7),那么该区域的更新就会被阻塞,直到合并完成或超过hbase.hstore.blockingWaitTime(默认90秒)所指定的时间为止。我们将它加大到了20,这对于写密集集群来说是一个相当大的值了。这样做的副作用是:会有更多的文件需要合并。
? ? ? ?这种调整通常会减少更新阻塞的发生机会。然而,正如我们刚才提到的那样,它也有副作用。建议在调整这些设置时务必小心,调整期间务必时刻观察写操作的吞吐量和延迟时间,这样才能找到最佳的配置值。
?
五、调整MemStore内存大小
? ? ? ?HBase的写操作会首先在所属区域的MemStore中生效,然后要等到MemStore的大小达到一定阀值之后才会被写入HDFS,从而省出一部分内存空间。MemStore的写盘操作以后台线程的方式运行,使用的是MemStore的快照。因此,即便是在MemStore写盘时,HBase仍可以一直处理写操作。这使得HBase的写入速度非常快。如果写操作的高峰值高到MemStore写盘都跟不上趟的程度,那么写操作填满MemStore的速度就会不断提高,而MemStore的总内存使用量也将继续升高。如果某一RegionServer中所有MemStore的总大小达到了某一可配置的阀值,更新又会被阻塞,并且强制进行写盘。
? ? ? ?调整MemStore总体内存的大小以避免发生更新阻塞。
vi $HBASE_HOME/conf/hbase-site.xml <property> <name>hbase.regionserver.global.memstore.upperLimit</name> <value>0.45</value> </property><property><name>hbase.regionserver.global.memstore.lowerLimit</name><value>0.4</value></property>
? ? ? ?hbase.regionserver.global.memstore.upperLimit属性控制了一台RegionServer中所有MemStore的总大小的最大值,超过该值后,新的更新就会被阻塞,并且强制进行写盘。这是一项可防止HBase在写入高峰时耗尽内存的配置信息。该属性默认为0.4,这意味着RegionServer堆大小的40%。
? ? ? ?该默认值在很多情况下都可以很好地发挥作用。但是,如果RegionServer日志中出现了许多含有Flush of region xxxx due to global heap pressure的日志,那么可能就需要调整该属性来处理这种高写入速度了。
? ? ? ?在第2步中,我们调整了hbase.regionserver.global.memstore.lowerLimit属性,它指定了何时对MemStores进行强制写盘,系统会一直进行写盘直到MemStore所占用的总内存大小低于该属性的值为止。其默认值是RegionServer堆大小的35%。
? ? ? ?在写密集集群中,调高这两个值有助于减少更新因MemStore大小限制而被阻塞的机会。另一方面,调整时必须十分小心,避免引发全垃圾回收或出现内存耗尽的错误。
? ? ? ?通常情况下,写密集集群上的读性能不像写性能那么重要。因此,我们可以为了优化写操作而调整集群。优化方法之一就是:减少分配给HBase块缓存的内存空间,将空间留给MemStore。关于如何调整块缓存的大小,请参见“调高读密集集群的块缓存大小”一节。
?
六、低延迟系统的客户端调节
? ? ? ?前面两节介绍的是避免服务器端阻塞的方法。可以帮助集群稳定、高性能地运行。服务器端的调整可以显著改善集群的吞吐量和平均延迟时间。
? ? ? ?然而,在低延迟系统和实时系统中,只进行服务器端的调优还不够。在低延迟系统中,长时间的停顿即使只是偶尔发生一两次也不可以接受。
? ? ? ?为了避免长时间的停顿,还要对客户端进行一些调节。
? ? ? ?在写密集集群中进行客户端调整的步骤如下。
vi $HBASE_HOME/conf/hbase-site.xml<property> <name>hbase.client.pause</name> <value>20</value></property><property> <name>hbase.client.retries.number</name> <value>11</value></property> <property> <name>hbase.ipc.client.tcpnodelay</name> <value>true</value></property> <property> <name>ipc.ping.interval</name> <value>4000</value></property>
? ? ? ?在第1步和第2步中调整hbase.client.pause和hbase.client.retries.number属性的目的是:让客户端在连接集群失败时能在很短的时间内迅速重试。
? ? ? ?hbase.client.pause属性控制的是让客户端在两次重试之间休眠多久。其默认值是1000毫秒(1秒)。hbase.client.retries.number属性用来指定最大重试次数。其默认值是10。
? ? ? ?每两次重试之间的休眠时间可按下面这个公式计算得出。
? ? ? ?pause_time =?hbase.client.pause * RETRY_BACKOFF[retries]
? ? ? ?其中,RETRY_BACKOFF是一个重试系数表,其定义如下。
? ? ? ?public static int?RETRY_BACKOFF[] = { 1,?1,?1,?2,?2,?4,?4,?8,?16,?32};
? ? ? ?在重试10次以后,HBase就会一直使用最后一个系数(32)来计算休眠时间。
? ? ? ?如果将暂停时间设为20毫秒,最大重试次数设为11,每两次连接集群重试之间的暂停时间将依次为:
? ? ? ?{ 20, 20, 20, 40, 40, 80, 80, 160, 320, 640, 640}
? ? ? ?这就意味着客户端将在2060毫秒内重试11次,然后放弃连接到集群。
? ? ? ?在第3步中,我们将hbase.ipc.client.tcpnodelay设为了true。此设置将禁止使用Nagle算法来进行客户端和服务器之间的套接字传输。
? ? ? ?Nagle算法是一种提高网络效率的手段,它会将若干较小的传出消息存在缓冲区中,然后再将它们一次全都发送出去。Nagle算法默认是启用的。低延迟系统应该将hbase.ipc.client.tcpnodelay设置为true,从而禁用Nagle算法。
? ? ? ?在第4步中,我们将ipc.ping.interval设为了4000毫秒(4秒),这样客户端和服务器之间的套接字传输就不会超时。ipc.ping.interval的默认值是1分钟,对于低延迟系统来说,这有点太长了。
? ? ? ?你也可以在客户端代码中使用org.apache.hadoop.hbase.HBaseConfiguration类来覆盖之前在hbase-site.xml中设置的各属性的值。下面代码可以实现与前面的第1步和第2步设定同样的效果。
Configuration conf = HBaseConfiguration.create();conf.setInt("hbase.client.pause", 20);conf.setInt("hbase.client.retries.number", 11);HTable table = new HTable(conf, "tableName");
? ? ? ?如果RegionServer上的可用内存较少,就应该将该属性设为一个较低的值。较低的值也适用于需要大量内存才能对请求进行处理的情形(比如将大值写入HBase或在大型缓存中扫描数据)。将hbase.regionserver.handler.count属性设为较高值意味着可以有更多的并发客户端,这可能会消耗掉很多RegionServer的内存,甚至有可能会用光所有的内存。
? ? ? ?如果每个请求只需要一点点内存,但每秒的交易次数(TPS)却很高,那么就应该将该属性设为一个较大的值,以使RegionServer可以处理更多的并发请求。
? ? ? ?在调整该属性的同时,建议启用RPC级的日志记录功能,然后监控每个RPC请求的内存使用情况和GC状态。
?
三、使用自定义算法预创建区域
? ? ? ?当我们在HBase中创建一张表时,该表一开始只有一个区域。插入该表的所有数据会保存在这个区域中。随着数据的不断增加,当该区域的大小达到一定阀值时,就会发生区域分割(Region Splitting)。这个区域会分成两半,以便使该表可以处理更多的数据。
? ? ? ?在写密集的HBase集群中,区域分割会带来以下几个需要解决的问题。
? ? ? ?分割/合并风暴问题。
? ? ? ?如果数据均匀地增长,大部分区域就会在同一时间发生分割,从而导致大量的磁盘I/O和网络流量。
? ? ? ?只有在分割出了足够多个区域之后,负载才会均衡。
? ? ? ?尤其是在表刚创建时,所有请求都会发给首个区域所在的那台RegionServer。
? ? ? ?对于第一个问题,可以参考“HBase基本性能调整”的“管理区域分割”一节,可通过手动分割的方法来解决。
? ? ? ?对于第二个问题,可以参考“在数据移入HBase前预创建区域”一节,可通过在创建表时预先创建好一些区域的方法来避免这一问题。使用HBase的RegionSplitter工具来预创建区域的方法。
? ? ? ?在默认情况下,RegionSplitter实用工具会使用MD5算法来生成MD5校验和,以此来作为区域的开始键。键值的范围是“00000000”到“7FFFFFFF”。这种算法(HexStringSplit)适用于很多情况,但在有些情况下,你可能更需要使用一种自己的算法来生成键值,以使负载能在集群中分散开来。
? ? ? ?HBase的行键完全由向HBase写入数据的应用程序所控制,在很多情况下,(由于这样或那样的原因)行键的范围和分布情况是可以预测的。因此,可以先计算出各区域的分割键,然后再使用这些分割键来创建预分割区域。
? ? ? ?我们将使用一组记录在文本文件中的区域开始键来创建表的预定义区域。
? ? ? ?1.创建一个split-keys文件。在该文件中输入一组区域分割键,每个键一行。假设该文件包含有如下一些开始键:
$ cat split-keysa0000affffb0000bffff
? ? ? ?2.创建Java类FileSplit,用它来实现org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm接口。
import org.apache.hadoop.hbase.util.Bytes;import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm;public class FileSplit implements SplitAlgorithm {//public static final String SPLIT_KEY_FILE = "split-keys";private String splitKeyFile;public FileSplit (String splitKeyFile) {this.splitKeyFile = splitKeyFile;}@Overridepublic byte[] split(byte[] start, byte[] end) {return null;}@Overridepublic byte[][] split(int numberOfSplits) {BufferedReader reader=null;try {List<byte[]> regions = new ArrayList<byte[]>();//一行一行读reader = new BufferedReader(new FileReader(splitKeyFile));String line;while ((line = reader.readLine()) != null) {//System.out.println(line);if (line.trim().length() > 0) {regions.add(Bytes.toBytes(line));}}return regions.toArray(new byte[0][]);} catch (IOException e) {throw new RuntimeException("Error reading splitting keys from " + splitKeyFile, e);} catch (Exception e) {e.printStackTrace();} finally {try {if (reader != null) reader.close();} catch (IOException e) {e.printStackTrace();}}return null;}@Overridepublic byte[] firstRow() {return null;}@Overridepublic byte[] lastRow() {return null;}@Overridepublic byte[] strToRow(String input) {return null;}@Overridepublic String rowToStr(byte[] row) {return null;}@Overridepublic String separator() {return null;}}
? ? ? ?3.编译该Java文件。
$ javac -classpath $HBASE_HOME/hbase-0.92.0.jar FileSplit.java
? ? ? ?4.将包含有分割键信息的split-keys文件复制到编译生成FileSplit类的目录下。
? ? ? ?5.运行如下脚本来在创建表的时候预创建一些区域。
$ export HBASE_CLASSPATH=$HBASE_CLASSPATH:./$ $HBASE_HOME/bin/hbase org.apache.hadoop.hbase.util.RegionSplitter -D split.algorithm=FileSplit -c 2 -f f1 test_table
? ? ? ?6.通过HBase的Web用户界面确认表和预定义区域是否已正确创建。
? ? ? ?HBase带有一个名为RegionSplitter的实用工具,该类可以用于:
? ? ? ?创建带预分割区域的HBase表? ? ? ?对现有的表中的所有区域进行滚动分割? ? ? ?使用自定义算法来分割区域
? ? ? ?为了能在创建表时分割区域,只需要像第2步那样实现一下split()方法。RegionSplitter类会调用该方法来对整张表进行分割。在我们的实现中,该方法会从我们准备好的文件中读取分割键(每个键一行),然后将它们转换并保存在一个存储该表所有初始区域的分割键的byte[]数组中。
? ? ? ?为了能使用该类来分割区域,我们将FileSplit类加入到了HBASE_CLASSPATH中,然后以带如下参数的方式调用了RegionSplitter实用程序。
? ? ? ?-D split.algorithm=FileSplit:指定分割算法。? ? ? ?-c 2:表分割的区域数。在本实现中没有用到。? ? ? ?-f f1:创建一个名为“f1”的列族。? ? ? ?test_table:待创建的表的名称。
? ? ? ?正如你在第6步中看到那样,我们用4个分割键将test_table分成了5个区域。这4个分割键正是我们写在split-keys文件中的内容。
? ? ? ?该表的其他属性都使用了默认值,你可以在HBase Shell中使用alter命令来修改其中的一些属性。
? ? ? ?请注意,即便是在对区域进行过分割之后,也仍然需要在应用层对行键进行设计,以避免将过多连续的行键写入同一个区域。你需要仔细地选择,找到一种适合你的数据访问模式的分割算法。
? ? ? ?该方法的另一个适用场景是用来提高将HBase表导出备份的数据导入回HBase的速度。
? ? ? ?你可以使用一个简单的脚本来备份各区域的开始键。有了FileSplit类,我们可以使用原来的这些键来恢复HBase表的区域边界,然后再以使用导出数据文件进行导入的方式来恢复数据。
? ? ? ?与将数据导入到同一个区域相比,这种方法能够显著提高数据恢复的速度,因为它会提前在多台RegionServer上恢复好多个区域,并且让这些区域均衡分布在多台RegionServer上。
?
四、避免写密集集群中的更新阻塞
? ? ? ?在写密集的HBase集群中,你可能会发现有写入速度不稳定的现象。大多数写操作都非常快,但有些写操作却非常慢。对于一个在线系统来说,无论平均速度如何,这种写入速度的不稳定都是不可接受的。
? ? ? ?导致这种情况的原因可能有两个:
? ? ? ?分割/合并使得集群的负荷非常高? ? ? ?更新操作被RegionServer给阻塞住了
? ? ? ?正如我们在“HBase基本性能调整”中描述的那样,你可以通过“禁用自动分割/合并,然后在低负载时手动进行分割/合并”的方式来避免分割/合并问题。
? ? ? ?要在RegionServer日志中进行一下查找,如果发现很多带“Blocking updates for ...”字样的消息,说明很可能就有很多更新都被阻塞住了,这样的更新操作的响应时间可能就是非常差。
? ? ? ?若要解决这类问题,必须同时对服务器端和客户端的配置作出调整,才能获得稳定的写入速度。
vi $HBASE_HOME/conf/hbase-site.xml <property> <name>hbase.hregion.memstore.block.multiplier</name> <value>8</value> </property><property><name>hbase.hstore.blockingStoreFiles</name><value>20</value></property>
? ? ? ?HBase写入操作的工作流程。
? ? ? ?数据的修改首先会被写入到了RegionServer的HLog(WAL预写日志)中,以此方式来持久化在HDFS中。然后,该修改被传给了宿主HRegion,然后传入到其所属列族的HStore的内存空间里(即MemStore)。当MemStore的大小达到一定阀值时,数据修改会被写入到HDFS上的StoreFile中。StoreFiles在内部使用HFile文件格式来存储数据。
? ? ? ?HBase是一种多版本并发控制(MVCC,Multiversion Concurrency Control)的架构。在更新/删除任何旧数据时,HBase都不会进行覆盖,而是给数据增加一个新版本。这使得HBase的写速度非常快,因为所有写操作都是顺序化的操作。
? ? ? ?如果HDFS上的小StoreFile太多,HBase就会启动合并操作来将它们重写为几个大一些的StoreFile,同时减少StoreFile文件的数量。当一个区域的大小达到一定阀值时,它又会被分成两个部分。
? ? ? ?为了防止合并/分割的时间过长并导致内存耗尽的错误,在某一区域的MemStore的大小达到一定阀值时,HBase会对更新进行阻塞。该阀值的定义为:
? ? ? ?hbase.hregion.memstore.flush.size 乘以?hbase.hregion.memstore.block.multiplier
? ? ? ?hbase.hregion.memstore.flush.size属性指定了MemStore在大小达到何值时会被写入到磁盘中。其默认值是128MB(0.90版本是64MB)。
? ? ? ?hbase.hregion.memstore.block.multiplier属性的默认值是2,这意味着,如果MemStore的大小达到了256MB(128 * 2),该区域上的更新将被阻塞。对于写密集集群的更新高峰期来说,这个值太小了,所以我们要调高该阻塞阀值。
? ? ? ?我们通常会让hbase.hregion.memstore.flush.size属性保持为默认值,然后将hbase.hregion.memstore.block.multiplier属性调整为一个较大的值(比如8),以此来提高MemStore阻塞阀值,减少更新阻塞发生的次数。
? ? ? ?请注意,调高hbase.hregion.memstore.block.multiplier会增大写盘时出现合并/分割问题的可能性,所以调整时一定要小心。
? ? ? ?第2步适用于另一种阻塞情况。如果任何一个Store的StoreFiles数(每个写盘MemStore一个StoreFile)超过了hbase.hstore.blockingStoreFiles(默认为7),那么该区域的更新就会被阻塞,直到合并完成或超过hbase.hstore.blockingWaitTime(默认90秒)所指定的时间为止。我们将它加大到了20,这对于写密集集群来说是一个相当大的值了。这样做的副作用是:会有更多的文件需要合并。
? ? ? ?这种调整通常会减少更新阻塞的发生机会。然而,正如我们刚才提到的那样,它也有副作用。建议在调整这些设置时务必小心,调整期间务必时刻观察写操作的吞吐量和延迟时间,这样才能找到最佳的配置值。
?
五、调整MemStore内存大小
? ? ? ?HBase的写操作会首先在所属区域的MemStore中生效,然后要等到MemStore的大小达到一定阀值之后才会被写入HDFS,从而省出一部分内存空间。MemStore的写盘操作以后台线程的方式运行,使用的是MemStore的快照。因此,即便是在MemStore写盘时,HBase仍可以一直处理写操作。这使得HBase的写入速度非常快。如果写操作的高峰值高到MemStore写盘都跟不上趟的程度,那么写操作填满MemStore的速度就会不断提高,而MemStore的总内存使用量也将继续升高。如果某一RegionServer中所有MemStore的总大小达到了某一可配置的阀值,更新又会被阻塞,并且强制进行写盘。
? ? ? ?调整MemStore总体内存的大小以避免发生更新阻塞。
vi $HBASE_HOME/conf/hbase-site.xml <property> <name>hbase.regionserver.global.memstore.upperLimit</name> <value>0.45</value> </property><property><name>hbase.regionserver.global.memstore.lowerLimit</name><value>0.4</value></property>
? ? ? ?hbase.regionserver.global.memstore.upperLimit属性控制了一台RegionServer中所有MemStore的总大小的最大值,超过该值后,新的更新就会被阻塞,并且强制进行写盘。这是一项可防止HBase在写入高峰时耗尽内存的配置信息。该属性默认为0.4,这意味着RegionServer堆大小的40%。
? ? ? ?该默认值在很多情况下都可以很好地发挥作用。但是,如果RegionServer日志中出现了许多含有Flush of region xxxx due to global heap pressure的日志,那么可能就需要调整该属性来处理这种高写入速度了。
? ? ? ?在第2步中,我们调整了hbase.regionserver.global.memstore.lowerLimit属性,它指定了何时对MemStores进行强制写盘,系统会一直进行写盘直到MemStore所占用的总内存大小低于该属性的值为止。其默认值是RegionServer堆大小的35%。
? ? ? ?在写密集集群中,调高这两个值有助于减少更新因MemStore大小限制而被阻塞的机会。另一方面,调整时必须十分小心,避免引发全垃圾回收或出现内存耗尽的错误。
? ? ? ?通常情况下,写密集集群上的读性能不像写性能那么重要。因此,我们可以为了优化写操作而调整集群。优化方法之一就是:减少分配给HBase块缓存的内存空间,将空间留给MemStore。关于如何调整块缓存的大小,请参见“调高读密集集群的块缓存大小”一节。
?
六、低延迟系统的客户端调节
? ? ? ?前面两节介绍的是避免服务器端阻塞的方法。可以帮助集群稳定、高性能地运行。服务器端的调整可以显著改善集群的吞吐量和平均延迟时间。
? ? ? ?然而,在低延迟系统和实时系统中,只进行服务器端的调优还不够。在低延迟系统中,长时间的停顿即使只是偶尔发生一两次也不可以接受。
? ? ? ?为了避免长时间的停顿,还要对客户端进行一些调节。
? ? ? ?在写密集集群中进行客户端调整的步骤如下。
vi $HBASE_HOME/conf/hbase-site.xml<property> <name>hbase.client.pause</name> <value>20</value></property><property> <name>hbase.client.retries.number</name> <value>11</value></property> <property> <name>hbase.ipc.client.tcpnodelay</name> <value>true</value></property> <property> <name>ipc.ping.interval</name> <value>4000</value></property>
? ? ? ?在第1步和第2步中调整hbase.client.pause和hbase.client.retries.number属性的目的是:让客户端在连接集群失败时能在很短的时间内迅速重试。
? ? ? ?hbase.client.pause属性控制的是让客户端在两次重试之间休眠多久。其默认值是1000毫秒(1秒)。hbase.client.retries.number属性用来指定最大重试次数。其默认值是10。
? ? ? ?每两次重试之间的休眠时间可按下面这个公式计算得出。
? ? ? ?pause_time =?hbase.client.pause * RETRY_BACKOFF[retries]
? ? ? ?其中,RETRY_BACKOFF是一个重试系数表,其定义如下。
? ? ? ?public static int?RETRY_BACKOFF[] = { 1,?1,?1,?2,?2,?4,?4,?8,?16,?32};
? ? ? ?在重试10次以后,HBase就会一直使用最后一个系数(32)来计算休眠时间。
? ? ? ?如果将暂停时间设为20毫秒,最大重试次数设为11,每两次连接集群重试之间的暂停时间将依次为:
? ? ? ?{ 20, 20, 20, 40, 40, 80, 80, 160, 320, 640, 640}
? ? ? ?这就意味着客户端将在2060毫秒内重试11次,然后放弃连接到集群。
? ? ? ?在第3步中,我们将hbase.ipc.client.tcpnodelay设为了true。此设置将禁止使用Nagle算法来进行客户端和服务器之间的套接字传输。
? ? ? ?Nagle算法是一种提高网络效率的手段,它会将若干较小的传出消息存在缓冲区中,然后再将它们一次全都发送出去。Nagle算法默认是启用的。低延迟系统应该将hbase.ipc.client.tcpnodelay设置为true,从而禁用Nagle算法。
? ? ? ?在第4步中,我们将ipc.ping.interval设为了4000毫秒(4秒),这样客户端和服务器之间的套接字传输就不会超时。ipc.ping.interval的默认值是1分钟,对于低延迟系统来说,这有点太长了。
? ? ? ?你也可以在客户端代码中使用org.apache.hadoop.hbase.HBaseConfiguration类来覆盖之前在hbase-site.xml中设置的各属性的值。下面代码可以实现与前面的第1步和第2步设定同样的效果。
Configuration conf = HBaseConfiguration.create();conf.setInt("hbase.client.pause", 20);conf.setInt("hbase.client.retries.number", 11);HTable table = new HTable(conf, "tableName");
发表评论
-
HBase安全及namespace操作
2015-09-18 19:37 48221、介绍 在HBase中,namespace命名空 ... -
How-to: Use HBase Bulk Loading, and Why
2015-06-26 16:46 1446Hbase对外提供随机、实时的读写访问大数据, ... -
HBase的Block Cache实现机制分析
2015-06-19 11:45 592本文结合HBase 0.94.1版本源码,对H ... -
hbase中的MSLAB
2015-06-19 10:21 1230CDH用MSLAB避免Hbas ... -
hbase优化(1)
2015-06-18 11:16 780因官方Book Performance Tuning部分章节 ... -
实时系统HBase读写优化--大量写入无障碍
2015-06-18 10:55 3907在使用hbase过程中发现在写入hbase的数据量很大时,经 ... -
hbase0.96—+版本的endpoint
2015-04-21 17:16 933HBase Coprocessor 之 endpio ... -
hbase observer
2015-04-21 10:28 1001Hbase自0.92之后开始支持 ... -
hbase block cache中的in-memory
2015-04-21 10:26 1185每load一个block到cache时,都会检查当前cache ... -
hbase0.94之后split策略
2015-04-18 15:57 841问题导读1.而在0.94版本之后,默认split策略修改为了 ... -
HBASE COPROCESSOR EndPoint实例
2015-04-18 15:26 1282问题导读:1、统计总行数,理想的方式应该是怎样?2、什么是E ... -
HBASE在QIHOO 360搜索中的应用
2015-04-07 14:10 1465【CSDN现场报道】中国IT ... -
HBase的long GC与 Zookeeper lease expired的权衡(转载)
2015-01-15 10:05 1814问题和现象:这是一个连锁反应:1)RegionServer在遇 ... -
hadoop+hbase+hive日常异常记录
2015-01-12 14:37 11221. 在hvie关联hbase创建外部表时报错: ... -
HBASE API高级特性
2014-12-22 18:17 1798一、过滤器 HBASE过滤器用来过滤数据,减少传输 ... -
HBASE 协处理器入门(转载)
2014-12-20 11:13 1032如果要统对hbase中的数据,进行某种统计,比如统计某个字段 ... -
HBASE数据架构
2014-12-17 09:38 21441、数据结构 关系数据库一般用B+树,HBA ... -
HBASE高级应用
2014-12-15 17:53 17301、行健或表设计 基本原则是尽量把查询的维度或信息 ... -
HBASE高级应用
2014-12-15 17:53 9241、行健或表设计 基本 ... -
HBASE ScannerTimeoutException 问题
2014-10-15 10:49 1242在对Hbase进行Scan的时候有时候会抛出ScannerT ...
相关推荐
总结来说,HBase写性能优化可以从多个方面入手,包括调整WAL写入机制、使用批量操作、合理分配Region、保证请求均衡以及控制KeyValue大小。每个策略都有其适用的业务场景和优势,系统管理员和开发者应根据实际需求和...
当region文件大小达到由“hbase.hregion.max.filesize”参数决定的上限(默认256MB),触发region split操作,原region一分为二,以提高数据读写效率与分布均衡性。 在此过程中,“.splits”目录的引入,有效避免了...
HBase 的性能优化是指对 HBase 的性能进行调整和优化,以提高其读写性能、减少延迟和提高系统的整体性能。以下是 HBase 中的一些性能优化策略: * IO 性能优化:HBase 中的 IO 操作是影响性能的关键因素。可以通过...
"HBase性能优化" HBase是一种高性能的NoSQL数据库,广泛应用于大数据存储和处理领域。然而,HBase的性能优化是非常重要的,特别是在大...HBase性能优化是非常重要的,需要根据实际情况调整各种参数和配置来提高性能。
本文将从表设计、写表、读表三个方面对 HBase 性能优化进行总结。 表设计 1. 预先创建 Regions 在创建 HBase 表的时候,默认情况下,HBase 会自动创建一个 region 分区。当导入数据的时候,所有的 HBase 客户端都...
2. **读写并发控制**:通过Zookeeper协调,避免并发写冲突,提高读写效率。 综上所述,HBase性能优化是一个综合性的任务,涉及硬件配置、数据模型设计、查询策略、运维管理等多个方面。只有全方位考虑并实践这些...
使用批量get接口能够减少客户端到RegionServer之间的RPC连接数,提高读取性能。需要注意的是,批量get请求要么成功返回所有请求数据,要么抛出异常。 再次,请求是否可以显示指定列族或列也是优化的关键点。HBase...
HBase在不同版本(1.x, 2.x, 3.0)中针对不同类型的硬件(以IO为例,HDD/SATA-SSD/PCIe-SSD/Cloud)和场景(single/batch, get/scan)做了(即将做)各种不同的优化,这些优化都有哪些?如何针对自己的生产业务和...
"HBase性能测试详细设计文档及用例" 本文档旨在详细介绍HBase性能测试的设计文档和实践经验,涵盖了HBase性能测试需要注意的一些参数设置和测试用例。下面是从该文档中提炼的相关知识点: 1.1 Pre-Creating ...
提高HBase客户端的读写性能可以通过多种方式进行。例如,启用bloomfilter过滤器,bloomfilter可以在查询时过滤掉不存在的行,这将显著提高查询性能;增加HBase堆内存,根据业务需求调整hbase-env.sh中的HBASE_HEAP...
在对HBase进行性能测试时,我们关注的关键指标包括数据读写速度、系统资源消耗以及MapReduce框架的运行效率。以下是对文档中提到的几个重要性能指标的详细解读: 1. **顺序写入(Sequential Write)**: - **FILE:...
7. **性能优化**:为了提高性能,HbaseTemplate允许批量操作,如批量插入或删除。通过构建Put或Delete对象列表,然后一次性提交,可以减少网络通信和HBase服务器的处理压力。 8. **异常处理**:在使用HbaseTemplate...
通过持续监控、调整配置和优化数据分布,可以显著提高HBase集群的读性能,减少延迟,并保证系统的稳定运行。在实际应用中,还应注意定期评估优化效果,以便及时调整策略,适应不断变化的业务需求。
HBase 主要用于处理大规模的数据集,特别适合于对性能和可伸缩性有极高要求的应用。它的设计灵感来源于 Google 的 Bigtable,是一个列式存储的数据库管理系统,利用了列族概念来优化数据库的读写性能和存储效率。 ...
上一篇文章主要介绍了HBase读性能优化的基本套路,本篇文章来说道说道如何诊断HBase写数据的异常问题以及优化写性能。和读相比,HBase写数据流程倒是显得很简单:数据先顺序写入HLog,再写入对应的缓存Memstore,当...
本人原创, 1.Hbase连接需要改Hbase包中的两个配置文件,加上Hbase所在机器ip及端口 2.HBaseDMLT初始化环境 3.MapDataIni为建表 4.MapDataInsert为写数据 5.MapDataDelete为删除数据 6.MapDataRead为读数据
1. **硬件优化**:增加内存、使用SSD硬盘、提高网络带宽,这些都可以显著提升HBase的性能。 2. **表设计**:合理设计RowKey,避免热点问题;预分区表以减少Region分裂;使用合适的数据类型和列族策略。 3. **HBase...
Cloud Serving Benchmark)是Yahoo开发的一个基准测试工具,用于评估云存储系统(如HBase)的性能。它提供了多种工作负载模型,模拟了不同的数据库访问模式,帮助用户全面了解系统的性能表现。 `ycsb-hbase12-...