HBase优化相关

接下来添加部分HBase优化相关的选择,先添加部分,后续实际工作中再补充完善。优化主要针对外界条件以及自身条件。

外界条件

外界条件包括硬件配置、GC、JVM等。

配置内存

HBase是吃内存的,很多地方都有涉及到,如blockcache读缓存,memStore写缓存,LSM树状结构和日志记录机制等都用到了内存,因此内存当然是越大越好,实际应用中会给HBase配置60~65%的物理内存。

配置CPU

当HBase中频繁使用过滤器,会涉及到计算,搜索和过滤等操作,这会比较耗费CPU,此外多条件组合扫描、使用压缩算法操作等,会给CPU带来压力,如果CPU性能低将有可能导致工作线程在阻塞等待状态。CPU主流2到8路,推荐使用双路四核CPU,一般的单核CPU至少需要四核。

GC收集器的选择

HBase是基于java编写的,GC回收器的选择也将影响整个程序的吞吐能力和停顿时间。以HotPot提供的虚拟机为例,它提供了多种新生代GC收集器+老年代GC收集器的组合选择,不同的组合,会有不同的应用场景。

对于HBase来说,它的出发点是低延迟的查询,因此需要有能提供低停顿时间的GC收集器,在老年代中CMS是一个不错的选择,而新生代中能跟它搭配使用的就只剩下Serial和ParNew,前者是老版本JDK的选择,是单线程的,而ParNew是基于多线程的,考虑更好性能,新生代中选择ParNew。

在hbase中通过hbase-env.sh来设置。

# 打开后,将使用ParNew+CMS+Serial Old的组合进行内存回收,Serial Old是备用的,当使用CMS出现大量Concurent Model Failure后,它会作为backup使用
export HBASE_OPTS="-XX:+UseConcMarkSweepGC"
# 设置CMS收集器在老年代空间被使用多少百分比后触发垃圾回收
# -XX:CMSInitiatingOccupancyFraction=70
# 设置CMS收集器在完成垃圾回收后是否要进行一次内存碎片整理
# -XX:+UseCMSCompactAtFullCollection"

JVM堆大小

堆大小一般设置不超过物理内存的一半,还要留下一部分内存给操作系统和Yarn。它也可以通过hbase-env.sh里来添加设置。

# 16384MB,默认16G
export HBASE_HEAPSIZE=16384

自身条件

自身就是配置hbase相关参数,根据使用场景进行必要调整。

datablock大小

datablock大小默认为64KB,可以在建表时指定,在列族层面进行设置,如下图设置为65536字节,即64KB。设置大,datablock有利于顺序读,设置小,则有利于字段度,根据实际的需要来调整。

根据HFile的结构,它包含datablock以及对应的dataindex和trailer,如果datablock设置小,则一个HFile索引内容就更多会更占空间,如果datablock设置大,则索引内容就少,相对来说HFile中能包含更多的数据。

# 建表时指定大小,单位为字节
hbase(main):0020> create 'star',{NAME => 'basic', BLOCKSIZE => '65536'}

blockcache关闭

blockcache默认是开启的,但是在顺序读的场景,如果读取的内容很多将很容易挤爆读缓存,如要读取1G的数据,这样的情况下开启blockcache不是最好的选择,它可能因此将本应该缓存以提高读取性能的数据挤出去,因此这种情况可以关闭它。

可以在新建表或者修改表时关闭blockcache。

hbase(main):0020> create 'star', {NAME => 'basic', BLOCKCACHE => 'false'}

bloom filter

布隆过滤器开启会提高读取速度,当查询某行是否在某个datablock时询问布隆过滤器,它将返回一个'确定不在'或者'不确定'的答案。除此之外,布隆过滤器还能精细到行级别和列标识符级别,如果使用行级别布隆过滤器,它可以判断某个行键是否在datablock中不存在,如果是列标识符级别布隆过滤器,它可以判断某个行和列标识符联合体是否在datablock中不存在。

但是使用它也是有代价的,因为布隆过滤器底层维系着一个byte数组,使用它势必会占用一定的空间,其中列标识符布隆过滤器的空间开销高于行级布隆过滤器。

可以在列族层面打开布隆过滤器。

# BLOOMFILTER默认为NONE,行级为ROW,列标识符级为ROWCOL
create 'star', {NAME => 'basic', BLOOMFILTER => 'ROWCOL'}

数据压缩开启

一般在CPU压力不大的情况下建议开启,因为数据的压缩和解压缩本身需消耗部分CPU资源。开启数据压缩后可以节省网络传输压力,主流的压缩算法为snappy、LZO、GZIP等,其中snappy是其中的佼佼者,它因为冠绝的压缩比和压缩速率让其他在座的压缩算法都变得'垃圾'。

在建表时可以在列族上打开压缩。

# 指定snappy算法
create 'star', {NAME => 'basic', COMPRESSION => 'SNAPPY'}

另外,数据只在硬盘上是压缩的,在内存中(memStore或blockcache)或在网络传输时是没有压缩的。要配置snappy等外来算法,需要编译配置,否则是不能使用的。

设置scan缓存

scan查询可以缓存,使用setCaching方法,这样可以减少客户端和服务端的交互,提升扫描查询的性能,下面是示意代码。

    //设置scan缓存
    @Test
    public void test() throws IOException {
        HTable table = new HTable(conf, TableName.valueOf("employer"));
        Scan scanner = new Scan();
        /* 设置cache,减少客户端和服务端的交互 */
        scanner.setBatch(0);
        scanner.setCaching(10000);
        ResultScanner rs = table.getScanner(scanner);
        //TODO,自定义
        rs.close();
    }

查询时指定列

hbase能提供百万列,因此如果查询行键对应的列数据很多时,服务端通过网络传输到客户端将耗费大量网络资源,如果能指定查询的列,将可以减少网络IO开销,下面是使用示意代码。

    //扫描时显示指定列
    @Test
    public void readColumn() throws IOException {
        HTable table = new HTable(conf, Bytes.toBytes("employer"));
        Scan scanner = new Scan();
        /* 指定列 */
        scanner.addColumn(Bytes.toBytes("basic"), Bytes.toBytes("name"));//name为列,basic为列族
        ResultScanner rsScanner = table.getScanner(scanner);
        //TODO,自定义
        rsScanner.close();
    }

关闭ResultScanner

上面示意代码中都需要关闭ResultScanner,因为它本质上是一个流,使用完后应该关闭释放资源,这点和JDBC类似。

使用批量读写

前面在记录hbase基本API使用中(https://www.cnblogs.com/youngchaolin/p/12179320.html),就有批量插入的的代码,hbase为我们提供了批量读和批量写的方法。HTable对象的put(List)和get(List)方法,都可以传入一个List集合,实现批量操作,这可以降低网络IO开销。

关闭写WAL日志

WAL日志设计的作用,是用来规避因为HRegionserver宕机而产生的数据丢失的风险,如果业务场景能承受这种风险,可以关闭写WAL日志。代码中可以通过Put实例对象的setWriteToWAL(false)来关闭。

    @Test
    public void putData() throws IOException {
        HTable table=new HTable(conf,TableName.valueOf("employer"));
        //添加数据
        //将每一条数据封装为put对象
        Put put=new Put("e1".getBytes());//给定rowKey
        //关闭写WAL日志
        put.setWriteToWAL(false);
        put.add("basic".getBytes(),"name".getBytes(),"clyang".getBytes());
        put.add("basic".getBytes(),"age".getBytes(),"28".getBytes());
        //添加数据
        table.put(put);
        //关流
        table.close();
    }

设置AutoFlush

HTable有一个属性AutoFlush,默认是true,即客户端每收到一条数据,立刻发送给服务端,这样是不高效的,可以将其关闭,先put请求缓存到客户端,最后再批量提交到服务端。有两种情况会批量提交,一是达到了write buffer size的阈值,一种是执行table.flushCommit()方法。

关闭AutoFlush有风险,当批量缓存到客户端后,在提交到服务端之前客户端宕机了,会导致缓存丢失,因此关闭它也是需要业务场景能容忍丢失数据。

    //关闭AutoFlush
    @Test
    public void autoFlush() throws IOException {
        HTable table=new HTable(conf,TableName.valueOf("employer"));
        //关闭AutoFlush功能,后面批量提交
        table.setAutoFlush(false);
        table.setWriteBufferSize(10*1024*1024);//10M
        //添加数据
        //将每一条数据封装为put对象
        Put put=new Put("e1".getBytes());//给定rowKey
        put.add("basic".getBytes(),"name".getBytes(),"clyang".getBytes());
        put.add("basic".getBytes(),"age".getBytes(),"28".getBytes());
        //TODO put不断添加数据,略了
        //添加数据
        table.put(put);
        //批量提交
        table.flushCommits();
        //关流
        table.close();
    }

预先创建HRegion

创建表时默认只有一个HRegion(默认10G),在导入大容量数据(假设200G)到hbase的场景下,可以预先创建HRegion,这样比自动分裂要更加的节省资源,因为自动分裂产生的HRegion数目会比预先创建的数目要多。可以通过hbase提供的RegionSplitter来执行操作,如下所示。

# star2是表名,HexStringSplit表示划分的算法,参数-c 10表示预创建10个Region,-f basic表示创建一个名字为basic的列族
[root@hadoop01 /home/software/hbase-0.98.17-hadoop2/bin] sh hbase org.apache.hadoop.hbase.util.RegionSplitter star2 HexStringSplit -c 10 -f basic

调整zookeeper session有效时长 

zookeeper session的有效时长,是在hbase-site.xml中设置的,默认是180s,这种时间一般需要修改。hbase的节点注册在zookeeper上,如果一个HRegionserver宕机,HMaster需要180s才能监听到,zookeeper会将这个HRegionserver从/hbase/rs节点中移除,HMaster会对被移除HRegionserver管理的HRegion进行balance,交给其他提供服务的HRegionserver来管理。一般会将这个时间设置小一些,参考《HBase权威指南》,可以在hbase-site.xml中添加如下设置。

<!--设置为30s,单位是ms,默认是180000ms-->
<
property> <name>zookeeper.session.timeout</name> <value>30000</value> </property>

以上是对HBase优化的初步学习,后续持续添加。

 

参考博文:

(1)《深入理解Java虚拟机》

(2)https://www.cnblogs.com/youngchaolin/p/12187151.html

(3)https://www.cnblogs.com/ukouryou/articles/2679559.html zookeeper session设置相关

(4)《HBase权威指南》zookeeper配置session相关

posted @ 2020-01-16 20:28  斐波那切  阅读(282)  评论(0编辑  收藏  举报