HBase笔记-5.HBase的优化

来源:互联网 发布:.net域名 编辑:程序博客网 时间:2024/06/05 20:06

1.表的设计

1.1 Pre-Creating Regions

默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候,所有的HBase客户端都向这一个region写数据,直到这个region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的regions,这样当数据写入HBase时,会按照region分区情况,在集群内做数据的负载均衡。
public static boolean createTable(HBaseAdmin admin, HTableDescriptor table, byte[][] splits)throws IOException {  try {    admin.createTable(table, splits);    return true;  } catch (TableExistsException e) {    logger.info("table " + table.getNameAsString() + " already exists");    // the table already exists...    return false;    }}public static byte[][] getHexSplits(String startKey, String endKey, int numRegions) {   //start:001,endkey:100,10region [001,010][011,020]  byte[][] splits = new byte[numRegions-1][];  BigInteger lowestKey = new BigInteger(startKey, 16);  BigInteger highestKey = new BigInteger(endKey, 16);  BigInteger range = highestKey.subtract(lowestKey);  BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegions));  lowestKey = lowestKey.add(regionIncrement);  for(int i=0; i < numRegions-1;i++) {    BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i)));    byte[] b = String.format("%016x", key).getBytes();    splits[i] = b;  }  return splits;}

1.2 Row Key

HBase中row key用来检索表中的记录,支持以下三种方式:-通过单个row key访问:即按照某个row key键值进行get操作;-通过row key的range进行scan:即通过设置startRowKey和endRowKey,在这个范围内进行扫描;-全表扫描:即直接扫描整张表中所有行记录。在HBase中,row key可以是任意字符串,最大长度64KB,实际应用中一般为10~100bytes,存为byte[]字节数组,一般设计成定长的。row key是按照字典序存储,因此,设计row key时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。举个例子:如果最近写入HBase表中的数据是最可能被访问的,可以考虑将时间戳作为row key的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE - timestamp作为row key,这样能保证新写入的数据在读取时可以被快速命中。Rowkey:1、大小越小越好2、值根据功能需求决定3、Row最好有散列原则。a)取反001      100 002      200010      010011      110b)Hash001—020

1.3 Column Family

不要在一张表里定义太多的column family。目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,它邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O。感兴趣的同学可以对自己的HBase集群进行实际测试,从得到的测试结果数据验证一下。

1.4 In Memory

创建表的时候,可以通过HColumnDescriptor.setInMemory(true)将表放到RegionServer的缓存中,保证在读取的时候被cache命中。

1.5 Max Version

创建表的时候,可以通过HColumnDescriptor.setMaxVersions(int maxVersions)设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置setMaxVersions(1)。

1.6 Time To Live

创建表的时候,可以通过HColumnDescriptor.setTimeToLive(int timeToLive)设置表中数据的存储生命期,过期数据将自动被删除,例如如果只需要存储最近两天的数据,那么可以设置setTimeToLive(2 * 24 * 60 * 60)。

1.7 Compact

HBase是一种Log-Structured Merge Tree架构模式,用户数据写入先写WAL,再写缓存,满足一定条件后缓存数据会执行flush操作真正落盘,形成一个数据文件HFile。随着数据写入不断增多,flush次数也会不断增多,进而HFile数据文件就会越来越多。然而,太多数据文件会导致数据查询IO次数增多,因此HBase尝试着不断对这些文件进行合并,这个合并过程称为Compaction。Compaction会从一个region的一个store中选择一些hfile文件进行合并。合并说来原理很简单,先从这些待合并的数据文件中读出KeyValues,再按照由小到大排列后写入一个新的文件中。之后,这个新生成的文件就会取代之前待合并的所有文件对外提供服务。HBase根据合并规模将Compaction分为了两类:MinorCompaction和MajorCompaction
Major Compaction是指将所有的StoreFile合并成一个StoreFile,这个过程还会清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。另外,一般情况下,Major Compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。因此线上业务都会将关闭自动触发Major Compaction功能,改为手动在业务低峰期触发。触发major compaction的可能条件有:major_compact 命令、majorCompact() API、region server自动运行hbase.hregion.majorcompaction 配置major合并的间隔时间,默认为1天,可设置为0,禁止自动的major合并,可手动或者通过脚本定期进行major合并hbase.hregion.majorcompaction.jetter 默认值为0.2 防止region server 在同一时间进行major compaction。该参数的作用是:对参数hbase.hregion.majorcompaction 规定的值起到浮动的作用,假如两个参数都为默认值24和0,2,那么major compact最终使用的数值为:19.2~28.8 这个范围。优化:1、关闭自动major compaction,hbase中通过hbase.hregion.majorcompaction=0来关闭major合并操作2、调用majorCompact() API/hbase shell中的major_compact命令
①调用majorCompact() API
HBaseAdmin admin = new HBaseAdmin(conf);admin.majorCompact(tableNameOrRegionName);
②hbase shell中的major_compact命令1.在Linux中新建一个*.rb(ruby文件),把hbase shell中的major_compact()操作直接放入这个ruby文件中去执行。.rb文件中:major_compact("tablename")  #一次只能执行一张表的major_compact操作2.写一个shell脚本文件,在shell中去执行这个ruby文件,当然(让这个ruby文件在hbaseshell中运行),利用crontab命令实现定时(凌晨3点)自动执行hbase的major_compact任务。.sh文件中:hbase shell   ./*.rb  #当然此处添加你自己的文件所在位置或者:major_compaction的脚本:取出所有table,一一执行major_compact:TMP_FILE=tmp_tablesTABLES_FILE=tables.txtecho "list" | hbase shell > tmp_tablessleep 2sed '1,6d' $TMP_FILE | tac | sed '1,2d' | tac > $TABLES_FILEsleep 2for table in $(cat $TABLES_FILE); do        echo "major_compact '$table'" | hbase shell        sleep 10done

Minor Compaction是指选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile,在这个过程中不会处理已经Deleted或Expired的Cell。一次Minor Compaction的结果是更少并且更大的StoreFile。minor compaction的运行机制要复杂一些,它由一下几个参数共同决定:hbase.hstore.compaction.min :默认值为 3,表示至少需要三个满足条件的store file时,minor compaction才会启动hbase.hstore.compaction.max 默认值为10,表示一次minor compaction中最多选取10个store filehbase.hstore.compaction.min.size 表示文件大小小于该值的store file 一定会加入到minor compaction的store file中hbase.hstore.compaction.max.size 表示文件大小大于该值的store file 一定会被minor compaction排除hbase.hstore.compaction.ratio 将store file 按照文件年龄排序(older to younger),minor compaction总是从older store file开始选择,如果该文件的size 小于它后面hbase.hstore.compaction.max 个store file size 之和乘以 该ratio,则该store file 也将加入到minor compaction 中。

2.写表操作

2.1 Auto Flush

通过调用HTable.setAutoFlush(false)方法可以将HTable写客户端的自动flush关闭,这样可以批量写入数据到HBase,而不是有一条put就执行一次更新,只有当put填满客户端写缓存时,才实际向HBase服务端发起写请求。默认情况下auto flush是开启的。

2.2 Write Buffer

通过调用HTable.setWriteBufferSize(writeBufferSize)方法可以设置HTable客户端的写buffer大小,如果新设置的buffer小于当前写buffer中的数据时,buffer将会被flush到服务端。其中,writeBufferSize的单位是byte字节数,可以根据实际写入数据量的多少来设置该值。

2.3 WAL Flag

在HBae中,客户端向集群中的RegionServer提交数据时(Put/Delete操作),首先会先写WAL(Write Ahead Log)日志(即HLog,一个RegionServer上的所有Region共享一个HLog),只有当WAL日志写成功后,再接着写MemStore,然后客户端被通知提交数据成功;如果写WAL日志失败,客户端则被通知提交失败。这样做的好处是可以做到RegionServer宕机后的数据恢复。因此,对于相对不太重要的数据,可以在Put/Delete操作时,通过调用Put.setWriteToWAL(false)或Delete.setWriteToWAL(false)函数,放弃写WAL日志,从而提高数据写入的性能。

2.4 批量写

通过调用HTable.put(Put)方法

3.读表操作

3.1 Scanner Caching

hbase.client.scanner.caching配置项可以设置HBase scanner一次从服务端抓取的数据条数,默认情况下一次一条。通过将其设置成一个合理的值,可以减少scan过程中next()的时间开销,代价是scanner需要通过客户端的内存来维持这些被cache的行记录。有三个地方可以进行配置,三者的优先级越来越高:1)在HBase的conf配置文件中进行配置;2)通过调用HTable.setScannerCaching(int scannerCaching)进行配置;3)通过调用Scan.setCaching(int caching)进行配置。

3.2 Scan Attribute Selection

scan时指定需要的Column Family,可以减少网络传输数据量,否则默认scan操作会返回整行所有Column Family的数据。3.3 Close ResultScanner通过scan取完数据后,记得要关闭ResultScanner,否则RegionServer可能会出现问题(对应的Server资源无法释放)。

3.4 批量读

调用HTable.get(Get)方法

3.5 Blockcache

HBase上Regionserver的内存分为两个部分,一部分作为Memstore,主要用来写;另外一部分作为BlockCache,主要用于读。写请求会先写入Memstore,Regionserver会给每个region提供一个Memstore,当Memstore满64MB以后,会启动 flush刷新到磁盘。当Memstore的总大小超过限制时(heapsize * hbase.regionserver.global.memstore.upperLimit * 0.9),会强行启动flush进程,从最大的Memstore开始flush直到低于限制。读请求先到Memstore中查数据,查不到就到BlockCache中查,再查不到就会到磁盘上读,并把读的结果放入BlockCache。由于BlockCache采用的是LRU策略,因此BlockCache达到上限(heapsize * hfile.block.cache.size * 0.85)后,会启动淘汰机制,淘汰掉最老的一批数据。一个Regionserver上有一个BlockCache和N个Memstore,它们的大小之和不能大于等于heapsize * 0.8,否则HBase不能启动。默认BlockCache为0.2,而Memstore为0.4。对于注重读响应时间的系统,可以将 BlockCache设大些,比如设置BlockCache=0.4,Memstore=0.39,以加大缓存的命中率。
原创粉丝点击