服务端调优
垃圾回收与JVM优化
Java本身提供了垃圾回收机制,依靠JRE对程序行为的各种假设进行垃圾回收。但是HBase支持海量数据持续入库,非常占用内存,因此繁重的负载会迫使内存分配策略无法安全地依赖于JRE的判断,主要调节的是RegionServer节点的JVM垃圾回收参数。
(1)HBASE_OPTS或者HBASE_REGIONSERVER_OPT变量来设置垃圾回收的选项,后面一般是用于配置RegionServer的,需要在每个子节点的HBASE_OPTS文件中进行配置。
- 设置新生代大小的参数,不能过小,过小则导致年轻代过快成为老年代,引起老年代产生内存随便。同样不能过大,过大导致所有的Java进程停止时间长。-XX:MaxNewSize=256m-XX:NewSize=256m 这两个可以合并成为-Xmn256m这一个配置来完成
- 设置垃圾回收策略:-XX:+UseParNewGC -XX:+UseConcMarkSweepGC也叫收集器设置,一般用于用于写在hbase-env.sh
- 设置CMS的值,占比多少时,开始并发标记和清扫检查。-XX:CMSInitiatingOccupancyFraction=70
- 内存大小:master默认为1G,可增加到2G,RegionServer默认1G,可调大到10G以上
(2)hbase.hregion.memstore.mslab.enabled默认值:true,这个是在hbase-site.xml中进行配置的值。说明:减少因内存碎片导致的Full GC,提高整体性能。
优化Region拆分合并以及预拆分Region
(1)hbase.hregion.max.filesize
在hbase-site.xml中进行配置,配置Region大小,0.94.12版本默认是10G,Region的大小与集群支持的总数据量有关系,如果总数据量小,单个Region太大,不利于并行的数据处理,如果集群需支持的总数据量比较大,Region太小,则会导致Region的个数过多,导致Region的管理等成本过高,如果一个RegionServer配置的磁盘总量为3T*12=36T数据量,数据复制3份,则一台RegionServer服务器可以存储10T的数据,如果每个Region最大为10G,则最多1000个region,因此默认配置还是比较合适的。如果要自己管理split,则应该调大该值,并且在建表时规划好Region数量和rowkey设计,进行Region预建,做到一定时间内,每个Region的数据大小在一定的数据量之下,当发现有大的Region,或者需要对整个表进行Region扩充时再进行split操作,这样可以在不同的Region上交错运行,分散I/O负载。
HBase配置文件
(1) hbase.regionserver.handler.count
该设置决定了处理RPC的线程数量,默认值是10。对于小负载的put或是get,delete等操作,handler数可以适当调大,比如:150。当请求内容很大(上MB,比如大的put、使用缓存的scans)的时候,如果该值设置过大则会占用过多的内存,导致频繁的GC,或者出现OutOfMemory,因此该值不是越大越好。
(2)hbase.regionserver.regionSplitLimit
控制最大的Region数量,超过则不可以进行split操作,默认是Integer.MAX,可设置为1,禁止自动的split,通过人工或者写脚本在集群空闲时执行。如果不禁止自动的split,则当Region大小超过hbase.hregion.max.filesize时会触发split操作(具体的split有一定的策略,不仅仅通过该参数控制,前期的split会考虑region数据量和memstore大小),每次flush或者compact之后,RegionServer都会检查是否需要Split,Split会先下线老Region再上线split后的Region,该过程会很快,但是会存在两个问题:1、老Region下线后,新Region上线前client访问会失败,在重试过程中会成功但是如果是提供实时服务的系统则响应时长会增加;2、split后的compact是一个比较耗资源的动作。
(3)hbase.hregion.memstore.flush.size
单个Region内所有的memstore大小总和超过指定值时,flush该Region的所有memstore到HDFS。
(4)hbase.hstore.blockingStoreFiles (默认7)
说明:在flush时,当一个region中的Store(CoulmnFamily)内有超过7个storefile时,则block所有的写请求进行compaction,以减少storefile数量。
调优:block写请求会严重影响当前regionServer的响应时间,但过多的storefile也会影响读性能。从实际应用来看,为了获取较平滑的响应时间,可将值设为无限大。
(5)hbase.hregion.memstore.block.multiplier(默认2)
说明:当一个region里总的memstore占用内存大小超过hbase.hregion.memstore.flush.size两倍的大小时,block该Region的所有请求,进行flush,释放内存。虽然设置了Region所占用的memstores总内存大小,比如64M,但在最后63.9M的时候,客户端Put了一个200M的数据,此时memstore的大小会瞬间暴涨到超过预期的hbase.hregion.memstore.flush.size的几倍。这个参数的作用是当memstore的大小增至超过hbase.hregion.memstore.flush.size 2倍时,block所有请求,直到降至该值以下。
调优: 正常应用场景不会出现突发写或写的量可控,保持默认值即可。如果正常情况下,写请求量就会经常暴长到正常的几倍,那么应该调大这个倍数,比如:4,并调整其他参数值,比如hfile.block.cache.size和hbase.regionserver.global.memstore.upperLimit/lowerLimit,以预留更多内存,防止HBase server OOM。不可太大,如果太大,则会增大导致整个RS的memstore内存超过memstore.upperLimit限制的可能性,进而增大阻塞整个RS的写的几率。如果region发生了阻塞会导致大量的线程被阻塞在到该region上,从而其它region的线程数会下降,影响整体的RS服务能力,
(6)hbase.regionserver.global.memstore.upperLimit(默认0.4)
当ReigonServer内所有region的memstores所占用内存总和达到heap的40%时,HBase会强制block所有的更新并flush这些region以释放所有memstore占用的内存。在以写为主的集群中,可以调大该配置项,不建议太大,因为block cache和memstore cache的总大小不会超过0.8,而且不建议这两个cache的大小总和达到或者接近0.8,避免OOM,在偏向写的业务时,可配置为0.45,memstore.lowerLimit保持0.35不变,在偏向读的业务中,可调低为0.35,同时memstore.lowerLimit调低为0.3,或者再向下0.05个点,不能太低,除非只有很小的写入操作,如果是兼顾读写,则采用默认值即可。
hbase.regionserver.global.memstore.lowerLimit(默认0.35)
同upperLimit,只不过lowerLimit在所有region的memstores所占用内存达到Heap的35%时,不flush所有的memstore。它会找一个memstore内存占用最大的region,做个别flush,此时写更新还是会被block。lowerLimit算是一个在所有region强制flush导致性能降低前的补救措施。在日志中,表现为 “Flushthread woke up with memory above low water”。
调优:这是一个Heap内存保护参数,默认值已经能适用大多数场景。
(7)hfile.block.cache.size(默认0.25)
涉及Hbase读取文件的主要配置,BlockCache主要提供给读使用。读请求先到memstore中查数据,查不到就到blockcache中查,再查不到就会到磁盘上读,并把读的结果放入blockcache。由于blockcache是一个LRU,因此blockcache达到上限(heapsize * hfile.block.cache.size)后,会启动淘汰机制,淘汰掉最老的一批数据。在偏向读的业务中,可以适当调大该值,比如设置blockcache=0.4,memstore=0.39,这会加大缓存命中率。
(8)hbase.regionserver.hlog.blocksize与hbase.regionserver.maxlogs
将这两个值放在一起,是因为WAL的最大值由hbase.regionserver.maxlogs* hbase.regionserver.hlog.blocksize (2GB by default)决定。一旦达到这个值,Memstore flush就会被触发。所以,当增加Memstore的大小以及调整其他的Memstore的设置项时,也需要去调整HLog的配置项。否则,WAL的大小限制可能会首先被触发,因而,将利用不到其他专门为Memstore而设计的优化。抛开这些不说,通过WAL限制来触发Memstore的flush并非最佳方式,这样做可能会会一次flush很多Region,尽管“写数据”是很好的分布于整个集群,进而很有可能会引发flush“大风暴”。
提示:最好将hbase.regionserver.hlog.blocksize* hbase.regionserver.maxlogs 设置为稍微大于hbase.regionserver.global.memstore.lowerLimit* HBASE_HEAPSIZE。
(9)hbase.hregion.majorcompaction
配置major合并的间隔时间,默认为1天,可设置为0,禁止自动的major合并,可手动或者通过脚本定期进行major合并,有两种compact:minor和major,minor通常会把数个小的相邻的storeFile合并成一个大的storeFile,minor不会删除标示为删除的数据和过期的数据,major会删除需删除的数据,major合并之后,一个store只有一个storeFile文件,会对store的所有数据进行重写,有较大的性能消耗。
(10)hbase.hstore.compactionThreshold
HStore的storeFile数量>= compactionThreshold配置的值,则可能会进行compact,默认值为3,可以调大,比如设置为6,在定期的major compact中进行剩下文件的合并。
(11)hfile.block.index.cacheonwrite:在index写入的时候允许put无根(non-root)的多级索引块到block cache里,默认是false,设置为true,读性能更好。
(12)列族、rowkey要尽量短,每个cell值均会存储一次列族名称和rowkey
(13)RergionServer的Region数量
一般每个RegionServer不要过1000,过多的Region会导致产生较多的小文件,从而导致更多的compact,当有大量的超过5G的region并且RergionServer总region数达到1000时,应该考虑扩容。
(14)建表时:
a、如果不需要多版本,则应设置version=1
b、开启lzo或者snappy压缩,压缩会消耗一定的CPU,但是,磁盘IO和网络IO将获得极大的改善,大致可以压缩4~5倍
c、合理的设计rowkey,在设计rowkey时需充分的理解现有业务并合理预见未来业务,不合理的rowkey设计将导致极差的hbase操作性能
d、合理的规划数据量,进行预分区,避免在表使用过程中的不断split,并把数据的读写分散到不同的RS,充分的发挥集群的作用
e、列族名称尽量短,比如:“f”,并且尽量只有一个列族
f、视场景开启bloomfilter,优化读性能
Client端调优
hbase.client.write.buffer
写缓存大小,默认为2M,推荐设置为6M,单位是字节,如果太大,则占用的内存太多
hbase.client.scanner.caching
scan缓存,默认为1,可根据具体的业务特征进行配置,原则上不可太大,避免占用过多的client和RegionServer的内存,一般最大几百,如果一条数据太大,则应该设置一个较小的值,通常是设置业务需求的一次查询的数据条数,比如:业务特点决定了一次最多100条,则可以设置为100
client应用读写分离
读和写分离,位于不同的tomcat实例,数据先写入redis队列,再异步写入Hbase,如果写失败再回存redis队列,先读Redis缓存的数据(如果有缓存,需要注意这里的Redis缓存不是Redis队列),如果没有读到再读Hbase。
当Hbase集群不可用,或者某个RegionServer不可用时,因为HBase的重试次数和超时时间均比较大(为保证正常的业务访问,不可能调整到比较小的值,如果一个RegionServer挂了,一次读或者写,经过若干重试和超时可能会持续几十秒,或者几分钟),所以一次操作可能会持续很长时间,导致tomcat线程被一个请求长时间占用,tomcat的线程数有限,会被快速占完,导致没有空余线程做其它操作,读写分离后,写由于采用先写Redis队列,再异步写Hbase,因此不会出现tomcat线程被占满的问题, 应用还可以提供写服务,如果是充值等业务,则不会损失收入,并且读服务出现tomcat线程被占满的时间也会变长一些,如果运维介入及时,则读服务影响也比较有限。
Scan查询编程优化:
1)、调整caching;
2)、如果是类似全表扫描这种查询,或者定期的任务,则可以设置scan的setCacheBlocks为false,避免无用缓存;
3)、关闭scanner,避免浪费客户端和服务器的内存;
4)、限定扫描范围:指定列簇或者指定要查询的列;
5)、如果只查询rowkey时,则使用KeyOnlyFilter可大量减少网络消耗;
用户在编写程序入库时,HBase的自动刷写是默认开启的,即用户每一次put都会提交到HBase server进行一次刷写,如果需要高速插入数据,则会造成I/O负载过重。这里可以关闭自动刷写功能,setAutoFlush(false)。如此,put实例会先写到一个缓存中,这个缓存的大小通过hbase.client.write.buffer这个值来设定缓存区,当缓存区被填满之后才会被送出。如果想要显示刷写数据,可以调用flushCommits()方法。采取这个方法要估算服务器端内存占用则可以:hbase.client.write.buffer*hbase.regionserver.handler.count得出内存情况。
关闭每次put上的WAL(writeToWAL(flase))。这样在刷写数据前,不需要预写日志,但是如果数据重要的话建议不要关闭。
hbase.client.scanner.caching:默认为1
这是设计客户端读取数据的配置调优,在hbase-site.xml中进行配置,代表scanner一次缓存多少数据(从服务器一次抓取多少数据来scan)默认的太小,但是对于大文件,值不应太大。
hbase.regionserver.lease.period默认值:60000
说明:客户端租用HRegion server 期限,即超时阀值。
调优:这个配合hbase.client.scanner.caching使用,如果内存够大,但是取出较多数据后计算过程较长,可能超过这个阈值,适当可设置较长的响应时间以防被认为宕机。
ZK调优
zookeeper.session.timeout
默认值3分钟,不可配置太短,避免session超时,Hbase停止服务,线上生产环境由于配置为1分钟,出现过2次该原因导致的Hbase停止服务,也不可配置太长,如果太长,当RegionServer挂掉,zookeeper不能快速知道,从而导致master不能及时对Region进行迁移。
zookeeper数量
至少5个节点。给每个zookeeper 1G左右的内存,最好有独立的磁盘。 (独立磁盘可以确保zookeeper不受影响).如果集群负载很重,不要把Zookeeper和RegionServer运行在同一台机器上面。就像DataNodes 和 TaskTrackers一样,只有超过半数的zk存在才会提供服务,比如:共5台,则最多只运行挂2台,配置4台与3台一样,最多只运行挂1台。
hbase.zookeeper.property.maxClientCnxns
zookeeper的最大连接数,默认为300,可配置上千
HDFS调优
1、dfs.name.dir: namenode的数据存放地址,可以配置多个,位于不同的磁盘并配置一个NFS远程文件系统,这样nn的数据可以有多个备份
2、dfs.data.dir:dn数据存放地址,每个磁盘配置一个路径,这样可以大大提高并行读写的能力
3、dfs.namenode.handler.count:nn节点RPC的处理线程数,默认为10,需提高,比如:60
4、dfs.datanode.handler.count:dn节点RPC的处理线程数,默认为3,可以调高这个处理线程数,比如:20,使得写数据更快
5、dfs.datanode.max.xcievers:dn同时处理文件的上限,默认为256,需提高,比如:8192
6、dfs.block.size:dn数据块的大小,默认为64M,如果存储的文件均是比较大的文件则可以考虑调大,比如,在使用hbase时,可以设置为128M,注意单位是字节
7、dfs.balance.bandwidthPerSec:在通过start-balancer.sh做负载均衡时控制传输文件的速度,默认为1M/s,可配置为几十M/s,比如:20M/s
8、dfs.datanode.du.reserved:每块磁盘保留的空余空间,应预留一些给非hdfs文件使用,默认值为0
9、dfs.datanode.failed.volumes.tolerated:在启动时会导致dn挂掉的坏磁盘数量,默认为0,即有一个磁盘坏了,就挂掉dn,可以不调整。
10、dfs.replication.interval
默认3秒,可以调高,避免hdfs频繁备份,从而提高吞吐率
11、dfs.datanode.socket.write.timeout
默认480秒,并发写数据量大的时候可以调高一些
12、dfs.socket.timeout
最好也要调高,默认的很小。同上,可以调高,提高整体速度与性能
本文详细介绍了HBase的服务端调优,包括JVM垃圾回收参数配置、Region拆分合并策略、HBase配置文件优化等。此外,还讨论了客户端的调优,如写缓存大小、scan缓存及读写分离策略,旨在提升HBase的性能和稳定性。
2564

被折叠的 条评论
为什么被折叠?



