这里主要讲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