hbase1.1.1 连接集群_Hadoop2.7.1+Hbase1.2.1集群环境搭建(7)hbase 性能优化【转】

安装NTP服务保证hbase集群机器时间时刻同步,最少不要大于30秒(hbase机器间时差默认值),因为hbase的表里默认列timestamp都需要用到机器时间,而作为分布式列式数据库,机器间时间统一很重要。

3.1.4 交换区

建议将 /proc/sys/vm/swappiness 设置为最大值 10或者0。默认值为 60。使用 sysctl 命令在运行时更改该设置并编辑 /etc/sysctl.conf,以在重启后保存该设置。

#vi /etc/sysctl.conf

vm.swappiness = 10

3.1.5 禁用透明大页面压缩

默认启用透明大页面压缩,可能会导致重大性能问题。请运行“echo never > /sys/kernel/mm/transparent_hugepage/defrag”以禁用此设置,然后将同一命令添加到 /etc/rc.local 等初始脚本中,以便在系统重启时予以设置。

#vi /etc/rc.local

echo never > /sys/kernel/mm/transparent_hugepage/defrag

3.2 网络

网络设备最低选择千兆网卡,最好万兆网卡;

性能好的交换机;

跨机房多机架部署Hadoop集群;

双电源确保断电故障。

3.3 java

3.3.1 JDK版本

JDK版本,首先要看hadoop对JDK版本要求,在hadoop2.7.1里要求最少JDK1.6+;

hbase里没明确说明,至少也是JDK1.6+;

目前多半是建议JDK1.8;

3.3.2 JVM参数调整

hbase基于HDFS之上,所以首先得优化HDFS内存,而HDFS里namenode节点内存直接决定你HDFS里最多文件个数,datanode里内存也相应要调整,最后是优化GC,在hadoop-env.sh里配置HADOOP_NAMENODE_OPTS和HADOOP_DATANODE_OPTS的内存和GC如下:

export HADOOP_NAMENODE_OPTS="-Xmx5g -Xms5g -Xmn256M -XX:SurvivorRatio=1 -XX:PermSize=128M -XX:MaxPermSize=128M -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false -XX:MaxTenuringThreshold=15 -XX:+CMSParallelRemarkEnabled -XX:+UseFastAccessorMethods -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+HeapDumpOnOutOfMemoryError -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintTenuringDistribution -Xloggc:/home/hadoop/hadoop-2.7.1/logs/gc-hadoop-namenode.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M"

export HADOOP_DATANODE_OPTS="-Xmx5g -Xms5g -Xmn256M -XX:SurvivorRatio=1 -XX:PermSize=128M -XX:MaxPermSize=128M -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false -XX:MaxTenuringThreshold=15 -XX:+CMSParallelRemarkEnabled -XX:+UseFastAccessorMethods -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+HeapDumpOnOutOfMemoryError -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintTenuringDistribution -Xloggc:/home/hadoop/hadoop-2.7.1/logs/gc-hadoop-datanode.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M"

3.4 hadoop优化

3.4.1 hadoop的HADOOP_NAMENODE_OPTS和HADOOP_DATANODE_OPTS优化

上面3.3.2里已经涉及

3.4.2 hadoop的HA

hbase是基于HDFS的,所以hadoop的尽量做hadoop HA部署,保证两个namenode(一个active 一个standby),保证HDFS故障后自动切换,高可用

3.4.3 hadoop的HDFS并发处理能力

hbase其实是HDFS的客户端,hbase的数据最终要落地到HDFS,所以并发处理HDFS的能力必须提升,下面的配置你必须优化:

hadoop的core-site.xml的io.file.buffer.size

hadoop的core-site.xml的io.compression.codecs

hadoop的hdfs-site.xml的dfs.namenode.handler.count

hadoop的hdfs-site.xml的dfs.datanode.handler.count

hadoop的hdfs-site.xml的dfs.datanode.max.transfer.threads

hadoop的hdfs-site.xml的dfs.datanode.balance.bandwidthPerSec

io.file.buffer.size

131072

io.compression.codecs

org.apache.hadoop.io.compress.SnappyCodec

dfs.namenode.handler.count

600

The number of server threads for the namenode.

dfs.datanode.handler.count

600

dfs.datanode.max.transfer.threads

409600

dfs.datanode.balance.bandwidthPerSec

52428800

3.5 zookeeper

zookeeper至少3台,其次最好奇数台,奇数是由zookeeper的少数服从多数的选举机制决定;

zookeeper.session.timeout默认为180秒,太长,修改zookeeper.session.timeout之前请首先一定要优化hbase的GC配置后才改此项值,hbase团队设置180秒是为了防止hbase初级使用者在不优化hbase GC的情况下,频繁因为GC导致hbase节点与zookeeper之间超时才设置的180秒,所以对于熟练者你改此值之前请确保你已经修改hbase GC。

3.6 hbase优化

3.6.1 hbase客户端优化

hbase客户端的源码我在另一篇博客源码解读--(1)hbase客户端源代码中进行介绍,了解源码只是为了让你能清醒的去优化hbase客户端。hbase客户端优化关键项目如下:

hbase客户端里传入hbase.client.write.buffer(默认2MB),加到客户端提交的缓存大小;

hbase客户端提交采用批量提交,批量提交的List的size计算公式=hbase.client.write.buffer*2/Put大小,Put大小可通过put.heapSize()获取,以hbase.client.write.buffer=2097152,put.heapSize()=1320举例,最佳的批量提交记录大小=2*2097152/1320=3177;

hbase客户端尽量采用多线程并发写

hbase客户端所在机器性能要好,不然速度上不去

下面是我当时在调研hbase时候做过的压测记录:

        操作hbase你只需在maven里引入如下依赖项:

org.apache.hbase

hbase-client

1.2.1

建议的客户端操作代码如下:

Configuration configuration = HBaseConfiguration.create();

configuration.set("hbase.zookeeper.property.clientPort", "2181");

configuration.set("hbase.client.write.buffer", "2097152");

configuration.set("hbase.zookeeper.quorum","192.168.199.31,192.168.199.32,192.168.199.33,192.168.199.34,192.168.199.35");

Connection connection = ConnectionFactory.createConnection(configuration);

Table table = connection.getTable(TableName.valueOf("tableName"));

try {

// Use the table as needed, for a single operation and a single thread

// construct List putLists

List putLists = new ArrayList();

for(int count=0;count<100000;count++){

Put put = new Put(rowkey.getBytes());

put.addImmutable("columnFamily1".getBytes(), "columnName1".getBytes(), "columnValue1".getBytes());

put.addImmutable("columnFamily1".getBytes(), "columnName2".getBytes(), "columnValue2".getBytes());

put.addImmutable("columnFamily1".getBytes(), "columnName3".getBytes(), "columnValue3".getBytes());

put.setDurability(Durability.SKIP_WAL);

putLists.add(put);

//3177不是我杜撰的,是2*hbase.client.write.buffer/put.heapSize()计算出来的

if(putLists.size()>=3177-1){

//达到最佳大小值了,马上提交一把

table.put(putLists);

putLists.clear();

}

}

//剩下的未提交数据,最后做一次提交

table.put(putLists)

} finally {

table.close();

connection.close();

}

3.6.2 hbase服务端优化

3.6.2.1 hbase服务端源代码对于内存的分配规律

1)Hbase内存分配=memstore(写)+blockcache(读)+other(其他)

2)Memstore占内存百分比(写)+blockcache占内存百分比(读)<=0.8

3)Memstore有两个临界点,第一个临界点是hbase.regionserver.global.memstore.size.lower.limit,默认=0.95,达到这个点,会选择当前region里memstore最大那个flushing;第二个临界点hbase.regionserver.global.memstore.size,默认=0.4,达到这个点,所有region做flushing;

4)Blockcache通过hfile.block.cache.size设置,默认=0.4

3.6.2.2 hbase内存配置多大合适

经验公式如下:

hbase.hregion.memstore.flush.size*单机hbase的region个数/hbase.regionserver.global.memstore.size/hbase.regionserver.global.memstore.size.lower.limit

举例如下:我的hbase要求写入快,读取速度在写入速度之后考虑,那么我把内存尽可能多的给到写,所以我调整hbase.regionserver.global.memstore.size=0.6,hbase.regionserver.global.memstore.size.lower.limit=0.6,hfile.block.cache.size=0.1,这样0.6+0.1<0.8首先没有违背hbase的大原则,hbase.hregion.memstore.flush.size=128MB保持不变毕竟HDFS的block刚好也是128MB,我预估每个机器最后单节点上负载hbase100个区,那么我hbase节点的内存要配置的最大值为128MB*100/0.6/0.6=35555MB=35GB,所以修改hbase-env.sh里如下配置:

export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS –Xmx35g –Xms35g –Xmn2g -XX:SurvivorRatio=1 -XX:PermSize=128M -XX:MaxPermSize=128M -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false -XX:MaxTenuringThreshold=15 -XX:+CMSParallelRemarkEnabled -XX:+UseFastAccessorMethods -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+HeapDumpOnOutOfMemoryError -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintTenuringDistribution -Xloggc:/home/hadoop/hbase-1.2.1/logs/gc-hbase-regionserver.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M"

3.6.2.3 hbase 服务端GC优化

配置详见3.6.2.2

3.6.2.4 hbase的split和预分区

hbase从设计那一刻起就要尽最大可能规避hbase的split操作,split的意思是hbase单区文件大小过大,需要拆分为两个文件,而避免hbase不做split的最好的办法就是提前预分区,一个预分区建表语句如下:

disable 'habsetest'

drop 'habsetest'

n_splits = 108

create 'hbasetest', {NAME => 'info', TTL=>'15552000', COMPRESSION => 'SNAPPY'}, {SPLITS => (1..n_splits).map {|i| "#{i*999/n_splits}"}}

最好的预分区是做到今后都不会发生split操作,那么预分区多少呢?这里有个逐步计算方法:

首先你要知道你这个hbasetest数据表数据保留多久,比如保留半年,也即180天;

第二步,你得观察每天数据量,例如每天hbasetest的数据量会产生10GB的数据;

第三步,你得知道你配置的单个region文件的大小,比如hbase.hregion.max.filesize=53687091200,意思是单个region最大50GB;

第四步,开始计算,180天的数据量=10GB*180*HADOOP备份数3=5400GB,这些数据占用分区数=108,

第五步,开始建表时候你就知道你必须在设计时候就得建立108个预分区同时设置数据只保留15552000秒之内的数据,也即保留180天内的数据,这样,只要你的估算准确,永远不会进行split操作,就算做,也只是少数一两个区split做而已,基本不影响hbase读写性能。

3.6.2.5 hbase的compact

hbase的memstore会不断刷小文件,而compact会不断合并小文件和清理过期数据和标记删除的数据,compact又分major compact和minor compact,我们要尽量关闭major compact变成手动在空闲期让它做major compact,

hbase.hregion.majorcompaction

0

禁止majorcompaction,这里虽然禁止了,但是还是得做,是通过linux定时任务在空闲时间执行

在hbase空闲期通过设置linux 的crontab定时任务来做major compact

cd /opt/hbase-1.2.1/bin

./hbase shell

major_compact 'hbasetest'

quit

3.6.2.6 合理设计rowkey

rowkey一定要设计合理,关于rowkey,你要理解如下:

hbase对于rowkey的处理是把rowkey按照ASCII码字典序来处理的,意思是ASCII对应的顺序字符的二进制顺序来处理,例如0-9字符的Byte值

hbase会按照这种ASCII字典序把rowkey和每个区的start rowkey和end rowkey对比,就知道该把这条记录写到哪个区

所以,rowkey的设计一定要尽量使得记录随机化离散化,不然会导致数据倾斜

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值