一、HBase关键参数配置指导
如果同时存在读和写的操作,这两种操作的性能会相互影响。如果写入导致的flush和Compaction操作频繁发生,会占用大量的磁盘IO操作,从而影响读取的性能。如果写入导致阻塞较多的Compaction操作,就会出现Region中存在多个HFile的情况,从而影响读取的性能。所以如果读取的性能不理想的时候,也要考虑写入的配置是否合理。
1、提升写效率
1.1客户端调优
1.1.1 AutoFlush
参数值:setAutoFlush
解析:
autoflush=false的原理是当客户端提交delete或put请求时,将该请求在客户端缓存,直到数据超过2M(hbase.client.write.buffer决定)或用户执行了hbase.flushcommits()时才向regionserver提交请求。因此即使htable.pu()执行返回成功,也并非说明请求真的成功了。假如还没有达到该缓存而client崩溃,该部分数据将由于未发送到regionserver而丢失。这对于零容忍的在线服务是不可接受的。
autoflush=true虽然会让写入速度下降2-3本,但是对于很多在线应用来说这都是必须打开的,也正是hbase为什么让它默认为true的原因,每次请求都会发往regionserver,而regionserver接收到请求后第一件事情就是写HLOG。因此对IO要求是非常高的,为了提高hbase的写入速度应该尽可能地提高IO吞吐量,比如增加磁盘、使用raid卡、减少replication因子数等。
如何调优?
经验设定:
setAutoFlush=false
1.1.2使用PutList方式提交请求
可以极大地提升写性能
1.2 Memstore相关
当regionserver(以下简称为RS)收到一个写请求,会将这个请求定位到某个特定的region。每一个region存储了一系列的Row,每一个Row对应的数据分散在一个或多个ColumnFamily(以下简称为CF)。特定CF的数据都存储在对应的store里面,而每个store都是由一个memstore和数个storefile组成。memstore存储在RS的内存中,而storefile则存储在HDFS上。当一个写请求到达RS的时候,该请求对应的数据首先会被menstore存储,直到达到一定的临界条件,memstore里面的数据才会flush到storefile。
使用memstore的主要原因是为了使存储在HDFS上的数据是有序的(按Row)。HDFS设计为顺序读写的,已有的文件不能被修改。这就意味着,因为hbase收到的写请求是无序的,所以如果直接将这些数据写到HDFS上,以后再对文件里面的内二做排序就会是一件极其困难的事情;无序的数据存储方式,又会大大影响后续的读请求性能。为了解决这种问题,hbase会将最近的某些写请求放到内存中(也就是memstore),并将这些数据在flush到storefile之前做好排序。
除了解决排序的问题,memstore还有其他好处,比如:
它能充当memcache的角色,缓存最近写入的数据。鉴于新数据的访问频率和几率都比旧数据高很多,这就大大的提高客户端的读效率。
注意:每个memstore每次刷新时,都会给CF生产一个storefile。
剩下读取就非常容易了,hbase会检查数据是否在memstore里面,否则就去storefile读取,然后返回给客户端。
1.2.1 根据memstore大小flush hfile
参数值:hbase.hregion.memstore.flush.size
参数解析:
在regionserver中,当写操作内存中存在超过memstore.flush.size大小的memstore,则MemstoreFlusher就启动flush操作将该memstore以hfile的形式写入对应的store中。
如何调优?
默认:128M
A、如果Regionserver的内存充足,而且活跃Region数量也不是很多的时候,可以适当增大该值,可以减少compaction的次数,有助于提升系统性能。
B、这种flush产生的时候,并不是紧急的flush,flush操作可能会有一定延迟,在延迟期间,写操作还可以进行,Memstore还会继续增大,最大值 = “memstore.flush.size” * "hbase.hregion.memstore.block.multiplier"。
C、当超过最大值时,将会阻塞写操作。适当增大“hbase.hregion.memstore.block.multiplier”可以减少阻塞,减少性能波动。
参数值:hbase.regionserver.global.memstore.size
参数解析:
RegionServer中,负责flush操作的是MemStoreFlusher线程。该线程定期检查写操作内存,当写操作占用内存总量达到阈值,MemStoreFlusher将启动flush操作,按照从大到小的顺序,flush若干相对较大的memstore,直到所占用内存小于阈值。
阈值=“hbase.regionserver.global.memstore.size” * "hbase.regionserver.global.memstore,size.lower.limit" * "Hbase_HEAPSIZE"
如何调优?
默认:0.4
该配置与“hfile.block.cache.size”的和不能超过0.8,也就是写和读操作的内存不能超过HeapSize的80%,这样可以保证除读和写以外其他操作的正常运行。
1.2.3 Flush前进行Compaction
参数值:hbase.hstore.blockingStoreFiles
参数解析:
在region flush前首先判断file文件个数,是否大于hbase.hstore.blockingStoreFiles。如果大于需要先Compaction并且让flush延时90s(这个参数可以通过hbase.hstore.blockingWaitTime进行配置),在延时过程中,将会继续写从而使得Memstore还会继续增大超过阈值(“memstore.flush.size” * "hbase.hregion.memstore.block.multiplier"),导致写操作阻塞。当完成Compaction后,可能就会产生大量写入。这样就导致性能激烈震荡。
如何调优?
默认:7
增加hbase.hstore.blockingStoreFiles,可以降低Block几率。
1.3 内存相关
Hbase利用内存完成读写操作。提高Hbase内存可以有效提高Hbase性能。
1.3.1 GC参数
参数值:GC_OPTS
参数解析:
GC_OPTS主要需要调整HeapSize的大小和NewSize的大小。
HMaster:
- -Xms512M -Xmx1G -XX:NewSize=64M -XX:MaxNewSize=128M
RegionServer:
- -Xms4G -Xmx6G -XX:NewSize=64M -XX:MaxNewSize=128M
如何调优?
A、挑战者HeapSize大小的时候,建议将Xms和Xmx设置成相同的值,这样可以避免JVM动态调整HeapSize大小的时候影响性能。
B、调整NewSize大小的时候,建议把其设置为HeapSize大小的1/9
C、HMaster:当HBase集群规模越大、Region数量越多时,可以适当调大HMaster的GC_OPTS参数。
D、RegionServer:RegionServer需要的内存一般比HMaster要大。在内存充足的情况下,HeapSize可以相对设置大一些。
经验设定:
主Hmaster的HeapSize为4G的时候,Hbase集群可以支持100000Region数的规模。根据经验值,单个RegionServer的HeapSize不建议超过20G。
1.4 HFile相关
1.4.1文件同步sync
参数值:hbase.regionserver.hfile.durable.sync
参数解析:
控制HFfile文件在写入到HDFS时的同步程度。如果为true,HDFS在把数据写入到硬盘后才返回:如果为false,HDFS在把数据写入OS的缓存后就返回。
如何调优?
默认为true
把该值设置为false比设为true时在写入性能上会更优。
1.5 Compaction相关
1.5.1Compact文件大小阈值
参数值:hbase.regionserver.thread.compaction.throttle
参数解析:
控制一次Minor Compaction时,进行compaction的文件总大小的阈值。
如何调优?
默认:1.5G
Compaction时的文件总大小会影响这一次compaction的执行时间,如果太大,可能会阻塞其他的compaction或flush操作。
1.5.2 Compact文件个数阈值
参数值:hbase.hstore.compaction.min
参数解析:
当一个Store中文件超过该值时,会进行compact。
如何调优?
默认:3
适当增大该值,可以减少文件被重复执行compaction,但是如果过大,会导致Store中文件数过多而影响读取的性能。
1.5.3 Compact文件数目
参数值:hbase.hstore.compaction.max
参数解析:
控制一次compaction操作时的文件数量的最大值。
如何调优?
默认:10
与“hbase.hstore.compaction.max.size”的作用基本相同,主要是控制一次compaction操作的时间不要太长。
1.5.4 Compact文件大小选择
参数值:hbase.hstore.compaction.max.size
参数解析:
如果一个HFle文件的大小大于该值,那么Minor Compaction操作中不会选择这个文件进行compaction操作,除非进行Major Compaction操作。
如何调优?
默认:2.5G
这个值可以防止较大的HFile参与Compaction操作。在禁止Major Compaction后,一个Store中可能存在几个HFile,而不会合并成一个HFile,这样不会对数据读取造成太大的性能影响。
1.5.5 Major Compaction执行周期
参数值:hbase.hregion.majorcompaction
参数解析:由于执行 Major Compaction 会占用较多的系统资源,如果正在处于系统繁忙时期,会影响系统的性能 。
如何调优?
默认: 24 小时
A. 如果业务没有较多的更新、删除、回收过期数据空间时, 建议设置为 0,以禁止Major Compaction。
B. 如果必须要执行 Major Compaction,以回收更多的空间,可以适当增加该值,同时配置参数“hbase.offpeak.end.hour”和“hbase.offpeak.start.hour”以控制 Major Compaction 发生在业务空闲的时期。
1.6 HLog相关
RS 上有一个 Write-ahead Log (以下简称 WAL),数据会持续的默认写到这个文件中。它包含了所有已经提交到 RS 的,已经保留在 memstore 中但是尚未 flush 到 storefile 的数据编辑历史。
这些在 memstore 中的,尚未持久化的数据,在 RS 发生错误时我们需要借助它进行恢复,它能重现这些尚未持久化的数据的编辑轨迹。 .
当 WAL(Hlog)变得非常大时,重现它的记录会花费非常多的时间。因此,我们需要限制WAL 的大小,当达到这个大小时,会触发 memstore 的 flush。
当数据 flush 到磁盘后,WAL 的大小就会变小,因为我们不需要再保存这些已经完成持久化的数据编辑记录。
1.6.1 文件同步sync
参数值:hbase.regionserver.wal.durable.sync
参数解析:
控制 HLog 文件在写入到 HDFS 时的同步程度。如果为 true, HDFS 在把数据写入到硬盘后才返回;如果为 false, HDFS 在把数据写入 OS 的缓存后就返回。
如何调优?
把该值设置为 false 比 true 在写入性能上会更优。
1.6.2 Hlog Flush条件
参数值:hbase.regionserver.maxlogs hbase.regionserver.hlog.blocksize
参数解析:
A、表示一个RegionServer上未进行Flush的Hlog的文件数量的阈值,如果大于该值,RegionServer会强制进行flush操作。
B、表示每个Hlog文件的最大大小。如果Hlog文件大小大于该值,就会滚动出一个新的Hlog,旧的将被禁用并归档。
如何调优?
这两个参数共同决定了RegionServer中可以存在的未进行Flush的hlog数量。WAL的最大容量 = hbase.regionserver.maxlogs * hbase.regionserver.hlog.blocksize。当达到这个容量的时候,memstore flush就会被触发。因此,你在调整memstore的设置的时候,你同样需要调整这些值来适应那些编号。否则,WAL容量达到限制可能导致memstore flush的罪魁祸首,你专门配置memstore参数所增加的资源可能永远无法被物尽其用。这个时候可以适当调整这两个参数的大小。以避免出现这种强制flush的情况。
经验设定:
hbase.regionserver.maxlogs:默认32,建议调整为100
hbase.regionserver.hlog.blocksize:默认64M,建议调整为128M
1.7 表设计相关
1.7.1压缩算法
参数值:COMPRESSION
参数解析:配置数据的压缩算法,这里的压缩是HFile中block级别的压缩。对于可以压缩的数据,配置压缩算法可以有效减少磁盘的IO,从而达到提高性能的目的。
如何优化?
默认:None
并非所有数据都可以进行有效的压缩。例如一张图片的数据,因为图片一般已经是压缩后的数据,所以压缩效果有限。推荐使用SNAPPY,因为它有较好的Encoding / Decoding 速度和可以接受的压缩率。
实例:create 'test_table',{NAME => 'cf1', COMPRESSION => 'SNAPPY'}
1.7.2 Block大小
参数值:BLOCKSIZE
参数解析:
配置HFile中block块的大小,不同的block块大小,可以影响HBase读写数据的效率。越大的block块,配合压缩算法,压缩的效率就越好;但是由于HBase的读取数据是以block块为单位的,所以越大的block块,对应随机读的情况,性能可能会比较差。
如何调优?
默认:64Kb
如果要提升写入性能,一般扩大到128kb或者256kb,可以提升写数据的效率,也不会影响太大的随机读性能。
实例:create 'test_table',{NAME => 'cf1', BLOCKSIZE => '32768'}
1.7.3 缓存内存
参数值:IN_MEMORY
参数解析:
配置这个表的数据有限缓存在内存中,这样可以有效提升读取的性能。
如何调优?
默认:false
对于一些小表,而且需要频繁进行读取操作的,可以设置此配置项
实例:create 'test_table',{NAME => 'cf1', IN_MEMORY => 'true'}
2、提升读效率
2.1 客户端调优
A、Scan数据时需要设置caching(一次从服务端读取的记录条数,默认是1),若使用默认值读性能会降到极低。
B、当不需要读一条数据所有列时,需要指定读取的列,以减少网络IO
C、只读取Rowkey时,可以为Scan添加一个只读取Rowkey的filter(FirstKeyOnlyFilter或者KeyOnlyFilter)。
D、在客户端代码中,可以设置caching和batch用来提升查询效率。
例如:Scan.setCaching(caching);scan.setBatch(batch); 当 caching 和 batch 都为 1 的时候,我们要返回 10 行具有 20 列的记录,就要进行 201 次 RPC, 因为每一列都作为一个单独的 Result 来返回,这样是我们不可以接受的(还有一次 RPC 是用来确认 scan 已经完成) 。
a) RPC 次数公式: RPCs = (Rows * Cols per Row) / Min(Cols per Row, Batch Size)/Scanner Caching
2.2 内存相关
Hbase利用内存完成读写操作。提高HBase内存可以有效提高HBase性能。
2.2.1 GC参数
参数值:GC_OPTS
参数解析:
GC_OPTS主要需要调整HeapSize的大小和NewSize的大小。
HMaster:
- -Xms512M -Xmx1G -XX:NewSize=64M -XX:MaxNewSize=128M
RegionServer:
- -Xms4G -Xmx6G -XX:NewSize=64M -XX:MaxNewSize=128M
如何调优?
A. 调整 HeapSize 大小的时候,建议将 Xms 和 Xmx 设置成相同的值,这样可以避免 JVM动态调整 HeapSize 大小的时候影响性能。
B. 调整 NewSize 大小的时候,建议把其设置为 HeapSize 大小的 1/9。
C. HMaster:当 HBase 集群规模越大、 Region 数量越多时,可以适当调大 HMaster 的GC_OPTS 参数。
D. RegionServer: RegionServer 需要的内存一般比 HMaster 要大。在内存充足的情况下,HeapSize 可以相对设置大一些。
经验设定:
主 HMaster 的 HeapSize 为 4G 的时候, HBase 集群可以支持 100000Region 数的规模。根据经验值,单个 RegionServer 的 HeapSize 不建议超过 20GB
2.3 缓存相关
参数值:hfile.block.cache.size
参数解析:
HBase缓存区大小,主要影响查询性能。根据查询模式以及查询记录分布情况来解决缓存区的大小。
如何调优?
默认:0.25
如果采用随机查询使得缓存区的命中率较低,可以适当降低缓存区大小。
3、关键参数配置指导--案例
3.1 活跃Region对集群的影响
HBase在设计上,遵循了LSM-TREE的原理:写数据阶段,尽最大努力先将每一个Region的数据保留在内存(MemStore)中,等达到一定的阈值(默认为128M)之后,再 将这些数据固化(Flush)到文件(HFile)中,在这过程中,为了保证数据的安全性,通过将数据写入到一个人日志文件(Hlog)中:
在当前时间段可能被写入用户数据的Region,称作“活跃"Region”。
举例:
如果一个用户表的Region是按天划分的,那么,第一天的用户数据,只会被写入到第一天的Region中,则这些Region就是活跃的Region。此时,对于其它天的Region,都处于一种“空闲”的状态。
集群中每一个物理节点的内存资源都是有限的,每一个Region的数据都是暂时先保留在内存中然后再固化到HFile文件中的,因此,我们需要控制一个时间段的活跃的Region数目。如果Region过多的话,会导致内存资源紧张,每一个Region在内存中的数据可能还没有达到预先设置阈值的大小就被提前触发Flush操作,这会导致Flush频率升高,产生大量的小HFile(小文件过多会导致读取性能的直线下降,也会加大Compaction的频率和压力)。相反活跃Region过少的话,也会导致并发度提升不上去,读写性能偏低。
如何设置最合理的活跃Region数目?
需要根据MemStore Flush的阈值大小,以及RegionServer堆内存的大小、预留MemStore空间的大小进行合理的计算。
如下列子可以说明这种计算方法:
经验举例:
假设分配给RegionServer堆内存的大小为8G,MemStore所占空间比例为40%,MemStore Flush的阈值大小为128M,则合理的活跃Region数目约为8*1024*0.4/128=26(个/节点)。
以用户交易记录表为例。每一条用户交易记录关联一个USER_ID,也关联一个确切的交易时间点。
如果我们在设计Key值的时候,采用“USER_ID+TIME”的格式,则划分Region的时候,一定会按照USER_ID的范围划分的。对于任意一天的交易记录,可能涉及到各个范围内的USER_ID,即可能涉及到所有的Region,因此所有的Region都可能是活跃的,就会导致前面提到的那种活跃Region过多的问题,而且这种问题会随着时间的持续而不断恶化下去。
如果RowKey采用格式“DAY+USER_ID_TIME”的话,Region一定是按天划分的,那么,第N天的用户交易记录数据只会设计到第N天的Region,也只有这一天的Region是活跃的,这样就有力的控制了活跃Region数目:
4、定位调优
4.1日志收集
日志分类介绍:
当前HBase的日志保存在/var/log/Bigdata/HBase和/var/log/Bigdata/audit/hbase目录下,具体如下:
4、2调优定位
对于读写性能定位和调优,主要查看Regionserver的hbase-XXX-regionserver-XXX.log 运
行日志。
日志中是否出现过以下信息?
**Flush thread woke up with memory above low water.
日志中出现这个信息说明有部分写过程出现过阻塞等待的现象,造成这个现象的原因是各个Region的Memstore使用的大小加起来超过了总的阈值,于是阻塞,并开始找一个Region进行Flush,,这个过程会需要消耗掉一段时间,通常来说造成这个的原因是单台Region server上的Region数太多了,因此单台Region server上最好不要放置过多的Region,一种调节方法是调大split的fileSize,这样可以适当的减少Region数,但需要关注调整后读性能的变化。
**delaying flush up to
当日志中出现这个信息时,可能会造成出现下面的现象,从而产生影响,这个通常是StoreFile太多造成的,通常可以调大点StoreFile个数的阈值。
**Blocking updates for
当日志中出现这个信息时,表示写动作已被阻塞,造成这个现象的原因是memStore中使用的大小已超过其阈值的2倍,通常是由于上面的delaving flush up to 造成的,或者是region数太多造成的,或者是太多的Hlog造成的,这种情况下会造成很大的影响,如内存够用的话,可以调大阈值,如果是其他原因,就对症下药。
4、3、定位调优思路
针对HBase读写变慢的场景,可以按照如下思路进行定位、调优:
开始-->对比性能差距-->查看监控信息-->查看相关日志-->确定具体场景-->进行参数调优-->后续观察
4.3.1通过客户端程序,记录写入、读取速度
在客户端程序中,可以记录HBase写入/读取速度,关注性能差距。或者,通过HMaster的页面来查看各个RegionServer的RPC请求。
4.3.2查看HBase监控信息
Region的分裂、compaction、flush次数过多、flush耗时高、硬件资源抢占等众多元素都会影响性能,因此,需要从Manager监控页面中,查看各个RegionServer的各类监控指标,需要重点关注:RegionServer GC时间、RegionServer GC次数、节点CPU/内存利用率、Compaction的次数,Flush文件次数、Flush操作的平均耗时、Split次数等信息。
4.3.3查看相关日志
结合HBase的监控信息,查看RegionServer的运行日志。
4.3.4举例
4.3.4.1背景说明
某个HBase测试集群,客户端主要是put写入操作,发现写入性能较慢。只有一张hbase表t1,表结构简单(一个cf,一个qualifier),建表时预分5个Region。
4.3.4.2性能差距比较
通过客户端put对t1表put数据计算出,单节点写入速度为416条/s左右。
4.3.4.3监控信息展示
发现各个RegionServer的flush次数较多
RegionServer的内存占用并不高
4.3.4.4日志分析定位
可以查看RegionServer的运行日志,发现Flush被延长90000ms字样:
2016-04-22 02:35:33,820 | WARN | MemStoreFlusher.0 | Region
t1,04,1461259167461.b6e781003392195313a5ec8e39c6bf77. has too many store files;
delaying flush up to 90000ms |
org.apache.hadoop.hbase.regionserver.MemStoreFlusher.flushRegion(MemStoreFlusher.jav
a:448)
初步分析结论:在内存利用不高的情况下,仍然有过多的Flush操作,并且看到有的Flush被延迟。因此,主要根据1.2章节内容,对MemStore相关参数,进行调优。
4.3.4.5参数调整&测试
调整前的参数为:
hbase.regionserver.global.memstore.size=0.1
hbase.hstore.blockingStoreFiles=2
调整后的参数为:
hbase.regionserver.global.memstore.size=0.4
hbase.hstore.blockingStoreFiles=7
调整后,用同样的客户端对同一张表 t1 进行 put 写入测试, 发现写入性能得到提升, 单
节点处理性能达到 1280 条/s
4、4常见问题处理
4.4.1 OOM(内存溢出)
4.4.1.1问题现象
当运行bulkload任务或开启Region操作时,在RegionServer端产生如下的日志:
“java.lang.OutOfMemoryError:Direct buffer memory”
4.4.1.2问题定位过程
由于各种操作,HBase需要许多内存。I/O操作实验direct buffer memory,因此为了更好的性能和提高并发数需要给RegionServer提供更多的direct buffer memory和heap memory。
检查JVM参数,按照使用场景增加heap memory(-Xms/-Xmx)和direct buffer memory(-XX:MaxDirectMemorySize)
4.4.1.3问题解决方法
增加heap memory和direct buffer memory来避免OutOfMemory异常
eg:-Xms32G -Xmx32G -XX:MaxDirectMemorySize=2048M
经验设定:
按照使用场景来修改GC_OPTS,RegionServer并发读写操作越多,需要的内存越大,经验表明一般地上述示例配置能支撑单个RegionServer支持30个长期并发的需求。