三、hbase–调优

这里主要讲hbase调优相关内容

一、Hmaster高可用

在HBase中Hmaster负责监控RegionServer的生命周期,均衡RegionServer的负载,如果Hmaster挂掉了,那么整个HBase集群将陷入不健康的状态,并且此时的工作状态并不会维持太久。所以HBase支持对Hmaster的高可用配置。
首先在 $HBASE_HOME/conf 下创建一个 backup-masters 名称的文件,注意,一定得是这个名字。文件内容是备Hmaster的主机名或者ip

vim backup-masters
bigdata122

接着把这个文件复制其他hbase节点的hbase的conf目录下

scp backup-masters bigdata122:/opt/modules/hbase-1.3.1/conf/
scp backup-masters bigdata123:/opt/modules/hbase-1.3.1/conf/

接着重启整个hbase集群

stop-hbase.sh
start-hbase.sh

接着通过 http://bigdata121:16010 可以看到备节点的情况
这会在zk的 hbase/backup-masters/节点下面以节点信息为名,创建一个节点,例如:

[zk: localhost:2181(CONNECTED) 6] ls /hbase/backup-masters 
[bigdata122,16000,1564564196379]

二、hadoop通用性优化

2.1 namenode元数据存储使用SSD
2.2 定时备份namenode上的元数据(如果配置了高可用就不需要了)

2.3 为namenode数据目录指定多个元数据目录
使用dfs.name.dir或者dfs.namenode.name.dir指定多个同样的元数据目录。这样可以提供元数据的冗余和健壮性,以免发生故障。具体配置可以看“namenode工作机制”这篇文章

2.4 NameNode的dir自恢复
设置dfs.namenode.name.dir.restore为true,允许尝试恢复之前失败的dfs.namenode.name.dir目录,在创建checkpoint时做此尝试,如果设置了多个磁盘,建议允许。

2.5 HDFS保证RPC调用会有较多的线程数
hdfs是使用rpc进行访问通信的,所以rpc调用的线程数决定了并发性能

hdfs-site.xml
属性:dfs.namenode.handler.count
解释:该属性是NameNode服务默认线程数,的默认值是10,根据机器的可用内存可以调整为50~100

属性:dfs.datanode.handler.count
解释:该属性默认值为10,是DataNode的处理线程数,如果HDFS客户端程序读写请求比较多,可以调高到15~20,设置的值越大,内存消耗越多,不要调整的过高,一般业务中,5~10即可。

2.6 hdfs副本数

hdfs-site.xml
属性:dfs.replication
解释:如果数据量巨大,且不是非常之重要,可以调整为2~3,如果数据非常之重要,可以调整为3~5。

2.7 hdfs文件块大小调整

hdfs-site.xml
属性:dfs.blocksize
解释:块大小定义,该属性应该根据存储的大量的单个文件大小来设置,如果大量的单个文件都小于100M,建议设置成64M块大小,对于大于100M或者达到GB的这种情况,建议设置成256M,一般设置范围波动在64M~256M之间。

2.8 MapReduce Job任务服务线程数调整

mapred-site.xml
属性:mapreduce.jobtracker.handler.count
解释:该属性是Job任务线程数,默认值是10,根据机器的可用内存可以调整为50~100

2.9 http服务器工作线程数

mapred-site.xml
属性:mapreduce.tasktracker.http.threads
解释:定义HTTP服务器工作线程数,默认值为40,对于大集群可以调整到80~100

2.10 文件排序合并优化

mapred-site.xml
属性:mapreduce.task.io.sort.factor
解释:文件排序时同时合并的数据流的数量,这也定义了同时打开文件的个数,默认值为10,如果调高该参数,可以明显减少磁盘IO,即减少文件读取的次数。在merge过程中,同时打开的文件数量越多,可以减少对磁盘的多次调用。

2.11 设置任务并发

mapred-site.xml
属性:mapreduce.map.speculative
解释:该属性可以设置任务是否可以并发执行,如果任务多而小,该属性设置为true可以明显加快任务执行效率,但是对于延迟非常高的任务,建议改为false,这就类似于迅雷下载。

2.12 MR输出数据的压缩

mapred-site.xml
属性:mapreduce.map.output.compress、    这是map输出mapreduce.output.fileoutputformat.compress   这是reduce输出
解释:对于大集群而言,建议设置Map-Reduce的输出为压缩的数据,而对于小集群,则不需要。

2.13 优化Mapper和Reducer的个数

mapred-site.xml
属性:
mapreduce.tasktracker.map.tasks.maximum
mapreduce.tasktracker.reduce.tasks.maximum
解释:以上两个属性分别为一个单独的Job任务可以同时运行的Map和Reduce的数量。
设置上面两个参数时,需要考虑CPU核数、磁盘和内存容量。假设一个8核的CPU,业务内容非常消耗CPU,那么可以设置map数量为4,如果该业务不是特别消耗CPU类型的,那么可以设置map数量为40,reduce数量为20。这些参数的值修改完成之后,一定要观察是否有较长等待的任务,如果有的话,可以减少数量以加快任务执行,如果设置一个很大的值,会引起大量的上下文切换,以及内存与磁盘之间的数据交换,这里没有标准的配置数值,需要根据业务和硬件配置以及经验来做出选择。
在同一时刻,不要同时运行太多的MapReduce,这样会消耗过多的内存,任务会执行的非常缓慢,我们需要根据CPU核数,内存容量设置一个MR任务并发的最大值,使固定数据量的任务完全加载到内存中,避免频繁的内存和磁盘数据交换,从而降低磁盘IO,提高性能。

大概估算公式:
map = 2 + ⅔cpu_core
reduce = 2 + ⅓cpu_core

三、Linux优化

3.1开启文件系统的预读缓存可以提高读取速度

sudo blockdev --setra 32768 /dev/sda

ra是readahead的缩写

3.2 关闭进程睡眠池
即不允许后台进程进入睡眠状态,如果进程空闲,则直接kill掉释放资源

sudo sysctl -w vm.swappiness=0

3.3 禁用Linux文件的atime
文件每次访问会更新atime(access time),而hdfs底层是一个block存储为一个文件,所以文件的数量是很多的,如果每次访问一次都刷新一次atime,其实没什么必要,可以将存储hdfs文件的设备的atime关闭掉。

vim /etc/fstab
UUID=6086522b-3bc7-44a2-83f4-fd79a8c4afa1 / ext4 errors=remount-ro,noatime,nodiratime 0 1

在工作参数中,添加noatime就是表示禁用atime

3.4 调整ulimit上限,默认值为比较小的数字

ulimit -n 查看允许最大进程数
ulimit -u 查看允许打开最大文件数

vi /etc/security/limits.conf 修改打开文件数限制
末尾添加:
*                soft    nofile          1024000
*                hard    nofile          1024000
Hive             -       nofile          1024000
Hive             -       nproc           1024000 

vi /etc/security/limits.d/20-nproc.conf 修改用户打开进程数限制
修改为:
#*          soft    nproc     4096
#root       soft    nproc     unlimited
*          soft    nproc     40960
root       soft    nproc     unlimited

3.5 开启集群时间同步
集群时间如果不同步,在节点心跳检查的时候,可能会有问题。

四、zookeeper优化

优化Zookeeper会话超时时间

hbase-site.xml
参数:zookeeper.session.timeout
解释:In hbase-site.xml, set zookeeper.session.timeout to 30 seconds or less to bound failure detection (20-30 seconds is a good start).该值会直接关系到master发现服务器宕机的最大周期,默认值为30秒(不同的HBase版本,该默认值不一样),如果该值过小,会在HBase在写入大量数据发生而GC时,导致RegionServer短暂的不可用,从而没有向ZK发送心跳包,最终导致认为从节点shutdown。一般20台左右的集群需要配置5台zookeeper。

五、hbase优化

5.1 预分区

​ 每一个region维护着startRowKey与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。那么依照这个原则,我们可以将数据索要投放的分区提前大致的规划好,以提高HBase性能。尽量将读写请求均衡地分发到不同分区的region中,这才是我们想要的。

数据倾斜查看:
在hbase的web页面中,可以点击每个table,然后进去查看表的在不同region的状态,其中有一列“request”,表示该表的不同的region接收到的请求个数。由此可以判断出不同region间是否存在数据倾斜。

分区方式:
(1)手动设定预分区

hbase> create 'staff','info','partition1',SPLITS => ['1000','2000','3000','4000']

这会分为5个区:
小于1000
1000~2000
2000~3000
3000~4000
大于4000

可以在hbase的web页面的table detials中点击对应的表,进去查看到每个表的分区情况。
也可以通过以下命令查看分区:

hbase(main):011:0> get_splits 'staff'
Total number of splits = 5

=> ["1000", "2000", "3000", "4000"]

(2)生成16进制序列预分区

create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

(3)根据文件设置的规则预分区
创建文件如下:
split.txt

aaaa
bbbb
cccc
dddd

创建表:

create 'staff3','partition3',SPLITS_FILE => 'splits.txt'

分区创建如下:
....~aaaa
aaaa~bbbb
bbbb~cccc
cccc~dddd
dddd~....

5.2 rowkey设计

一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。接下来我们就谈一谈rowkey常用的设计方案。而且rowkey的设计越随机越好,越没有规律越好,这样才能更加随机的分布到不同region中,从而均衡读写压力

5.2.1 生成随机数、hash、散列值

比如:
原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7
原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd
原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913
在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。

5.2.2 字符串反转

常用一些有规律的数据,将其变为较弱规律的数据,常见的比如电话号码、identification card号码、日期时间等。这些数据都是有规律,而将他们反转后,就相对随机一些了。

这样也可以在一定程度上散列逐步put进来的数据。

5.2.3 字符串拼接

rowkey本身有规律,也可以在前面或者后面添加一些随机字符,将rowkey规律打乱,变成较为随机的数据

5.3 内存优化

因为hbase 作为一款内存型的nosql,对内存的使用量是很大的,那么如果规划内存与hbase的性能密切相关。内存优化这方面主要集中在3个方面:compact、flush以及内存区域规划

5.3.1 compact

compact操作就是将多个storefile合并,主要是为了压缩存储空间,提高读写速度。根据合并的规模,分为 Minor Compaction 和 Major Compaction
Minor Compaction:

是指选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile,在这个过程中不会处理已经Deleted或Expired的Cell。一次Minor Compaction的结果是更少并且更大的StoreFile。

Major Compaction

是指将所有的StoreFile合并成一个StoreFile,这个过程还会清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。另外,一般情况下,Major Compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。因此线上业务都会将关闭自动触发Major Compaction功能,改为手动在业务低峰期触发

minor compaction通常会由memstore flush,线程定期检查触发。major compaction通常会由手动触发,可以通过参数,hbase.hregion.majorcompaction设置为0即可,默认时间为一天86400000。

手动compact操作:
Minor Compaction

compact 'namespace:table','cf'
如果不指定cf,就会合并整个region

Major Compaction

major_compact 'namespace:table','cf'   用法和上面类似

5.3.2 flush

flush就是从memstore将数据刷写到storefile中,hbase写数据,先写wal的hlog,成功后才写memstore,每个列只有多有一个memstore,当一个region所有cf的memstore大小之和达到hbase.regionserver.global.memstore.size设置的大小时,这个值默认是128M,就会flush。当前单个cf 的memstore达到这个值也会flush的,这种非实时的flush操作主要是为了较好的写性能,避免每次写都要flush到hdfs中。在hbase2.0版本中,memstore其实是由一个可变的memstore和许多不可变的memstore组成,直接在内存中进行compaction,如果flush成HFile,再compaction,会占用大量磁盘和网络IO。

5.3.3 内存规划

如何分配合适的内存给regionserver,以及regionserver内部不同功能性内存的大小需要是很考究的。可以大致分为以下几个区域的内存:

CombinedBlockCache:
负责读缓存,分为 LRUBlockCache和BucketCache。前者一般用来缓存数据的元数据,而且属于堆内内存,后者用来缓存原始数据,属于堆外内存.

memstore:
负责写缓存,用来存储可以直接修改的数据的

other:
用于存储hbase工作过程中的对象

jvm_heap:
就是减去BucketCache后的大小。一般就是 memstore+LRUBlockCache+other

有一个硬性要求:LRUBlockCache + MemStore < 80% * JVM_HEAP
不满足这个条件,rs直接无法启动

分为两种场景:读少写多,读多写少。
1、读少写多

一般用 LRUBlockCache 模式,也就是 LRUBlockCache + memstore + other的模式。
都在堆内内存中。

以机器内存为96G为例,一般分配给rs的 2/3的内存,也就是64G。
首先memstore要比LRUBlockCache大,且LRUBlockCache + MemStore < 80% * JVM_HEAP
推荐以下规划:
MemStore = 45% * JVM_HEAP = 64G * 45% = 28.8G ,LRUBlockCache = 30% * JVM_HEAP = 64G * 30% = 19.2G;默认情况下Memstore为40% * JVM_HEAP,而LRUBlockCache为25% * JVM_HEAP

jvm参数配置:

-XX:SurvivorRatio=2  -XX:+PrintGCDateStamps  -Xloggc:$HBASE_LOG_DIR/gc-regionserver.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M -server -Xmx64g -Xms64g -Xmn2g -Xss256k -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+UseParNewGC -XX:MaxTenuringThreshold=15  -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:-DisableExplicitGC

其中 -Xmx64g -Xms64g 设置堆内存为 64g

hbase-stie.xml中的配置

<!--memstore的配置-->
由上述定义可知,hbase.regionserver.global.memstore.upperLimit设置为0.45,hbase.regionserver.global.memstore.lowerLimit设置为0.40
hbase.regionserver.global.memstore.upperLimit表示RegionServer中所有MemStore占有内存在JVM内存中的比例上限。如果所占比例超过这个值,RS会首先将所有Region按照MemStore大小排序,并按照由大到小的顺序依次执行flush,直至所有MemStore内存总大小小于hbase.regionserver.global.memstore.lowerLimit,一般lowerLimit比upperLimit小5%。
<property>
    <name>hbase.regionserver.global.memstore.upperLimit</name>
    <value>0.45</value>
</property>
<property>
    <name>hbase.regionserver.global.memstore.lowerLimit</name>
    <value>0.40</value>
</property>

<!--LRUBlockCache的配置-->
<property>
    <name>hfile.block.cache.size</name>
    <value>0.3</value>
</property>

2、读多写少

一般用BucketCache,也就是读内存包括 BucketCache和 LRUBlockCache。两者共同构成CombinedBlockCache
采用以下内存分布:
堆内内存:LRUBlockCache + memstore + other
堆外内存:BucketCache

以机器内存为96G为例,一般分配给rs的 2/3的内存,也就是64G。也可以更多的
这种情况,读、写、其他内存的比例一般为 5:3:2,读内存中 LRU:BUCKET= 1:9
同时要满足 LRUBlockCache + MemStore < 80% * JVM_HEAP
CombinedBlockCache 64* 0.5=32
-----LRUBlockCache  32*0.1
-----BucketCache    32*0.9
memstore           64*0.3
heap               64 - 32*0.9
计算之后,LRU + MemStore / JVM_HEAP = 3.2G + 19.2G / 35.2G = 22.4G / 35.2G =  63.6% ,远小于80%。因此需要调整一下对应的大小。这种情况证明堆内存太大了,适量减少JVM_HEAP值(减少至30G),增大Memstore到20G。因为JVM_HEAP减少了,堆外内存就需要适量增大,因此将BucketCache增大到30G。
调整之后,LRU + MemStore / JVM_HEAP = 3.2G + 20G / 30G = 23.2G / 30G =  77%

jvm参数设置

-XX:SurvivorRatio=2  -XX:+PrintGCDateStamps  -Xloggc:$HBASE_LOG_DIR/gc-regionserver.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M -server -Xmx40g -Xms40g -Xmn1g -Xss256k -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+UseParNewGC -XX:MaxTenuringThreshold=15  -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:-DisableExplicitGC

hbase-site.xml配置

memstore相关:
根据upperLimit参数的定义,结合上述内存规划数据可计算出 upperLimit =  20G / 30G = 66%。因此upperLimit参数设置为0.66,lowerLimit设置为0.60
<property>
    <name>hbase.regionserver.global.memstore.upperLimit</name>
    <value>0.66</value>
</property>
<property>
    <name>hbase.regionserver.global.memstore.lowerLimit</name>
    <value>0.60</value>
</property>

CombinedBlockCache相关:
<property> 设置为堆外内存
    <name>hbase.bucketcache.ioengine</name>
    <value>offheap</value>
</property>
<property> 堆外内存大小
    <name>hbase.bucketcache.size</name>
    <value>34816</value>
</property>
<property> bucketcache的比例
    <name>hbase.bucketcache.percentage.in.combinedcache</name>
    <value>0.90</value>
</property>

更加详细的请看:http://hbasefly.com/2016/06/18/hbase-practise-ram/ 写的超好。

5.4 基础优化

1、允许hdfs文件中追加内容

hdfs-site.xml、hbase-site.xml
属性:dfs.support.append
解释:开启HDFS追加同步,可以优秀的配合HBase的数据同步和持久化。默认值为true。

2、优化DataNode允许的最大文件打开数

hdfs-site.xml
属性:dfs.datanode.max.transfer.threads
解释:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为4096或者更高。默认值:4096

3、优化延迟高的数据操作的等待时间

hdfs-site.xml
属性:dfs.image.transfer.timeout
解释:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉

4、优化DataNode存储

属性:dfs.datanode.failed.volumes.tolerated
解释: 默认为0,意思是当DataNode中有一个磁盘出现故障,则会认为该DataNode shutdown了。如果修改为1,则一个磁盘出现故障时,数据会被复制到其他正常的DataNode上,当前的DataNode继续工作。

5、设置regionserver的RPC监听数量

hbase-site.xml
属性:hbase.regionserver.handler.count
解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

6、优化HStore文件大小

属性:hbase.hregion.max.filesize
解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个。

7、优化hbase客户端缓存

hbase-site.xml
属性:hbase.client.write.buffer
解释:用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。

8、指定scan.next扫描HBase所获取的行数

hbase-site.xml
属性:hbase.client.scanner.caching
解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/194591.html

(0)
上一篇 2021年11月16日
下一篇 2021年11月16日

相关推荐

发表回复

登录后才能评论