HBase优化

一、IOT表的优化

1、IOT表现状

  • IOT数据采集表

    • 采集IOT设备每秒钟数据,存入hbase,rowkey为时间戳+设备名按时间进行预分区

    • 其中,一张IOT表里,有10个设备每秒钟采集6个自己区域的监测值,一天的数据为10*(60*60*24) = 844000条数据

    • 列为:每个设备的监测区域ID(如AacW6cTXG20、AacW6cTXG21、AacW6cTXG23…)+ 设备ID,一共10*6+1=61列。

    • 如果,要通过Pheonix查询,需要在pheonix中建立相应映射表。直接查habse中的表,pheonix会显示表不存在。

  • IOT状态记录表:

    • 保存每5分钟计算的结果,rowkey为时间戳+设备名,没有预分区
    • 直接通过pheonix建立的表,可直接通过pheonix进行增删改查,但预分区不能指定。
    • 可通过在创建表时,指定SALT_BUCKETS来实现pre-split(预分割)。
      • 但是,如果通过Phoenix创建了一个salted table,那么只有通过Phoenix SQL插入数据才能使得被插入的原始rowkey前面被自动加上一个byte,通过HBase shell插入数据无法prefix原始的rowkey。参考
    CREATE TABLE IF NOT EXISTS TEST_IOT_STATE (  
        TIME             VARCHAR not null,  
        DEVICEID         VARCHAR not null,        
        PERMISSION       VARCHAR ,    
        ONLINE           INTEGER,    
        OFFLINE          INTEGER,  
        ERROR            INTEGER, 
        STANDBY          INTEGER,
        CONSTRAINT pk PRIMARY KEY (TIME,DEVICEID)) COMPRESSION = 'GZ', SALT_BUCKETS = 6;
    
  • 在开始阶段,数据量较小,数据读写没有问题,

  • 当数据累积达到一定程度时,出现读性能差,查不出数据的现象。
    HBase优化_第1张图片

HBase优化_第2张图片

2、分析思路

  • 查询rowkey与预分区的设置,观察各分区数据请求状态,发现数据请求集中于第一个分区,第一个分区写满后,又开始了第二个分区,
  • 可能出现了**数据“热点”**问题,多个IOT设备同时写入一个服务器一个分区(node01的第一分区),又同时进行读操作。
  • 造成服务器的计算与IO资源紧张,可能会请求延时。

HBase优化_第3张图片

3、解决思路

  • 现阶段IOT表,行键为:时间戳+设备ID,预分区策略为:时间跨度。
    • 优点:对查询有益,可以按照时间进行rowkey的范围查询,
    • 不足: 数据不断增大,到一定程度,会出现数据热点,导致负载不均衡
  • 并且,按照时间跨度进行预分区,
    • 如果region分区时设置的时间跨度大,写入数据超过region的阈值,会触发split,消耗IO与运算性能。
    • region设置的时间跨度太小,很容易写满前面的分区,在最后一个分区里堆积,到一定数量时触发split。
  • 实际数据量较大的情况下,一般都考虑了负载均衡,让数据均匀写入各服务器的各分区,体现分布式思想。
    • hbase中,一般是通过“rowkey设计+预分区策略”,实现负载均衡

4、实现方法

  • 进行rowkey散列设计,与预分区策略设计

  • 设计目的:

    • 按一定的规则,将数据均匀分布在各个分区中,并能够按一定时间范围进行多维查询
  • rowkey散列设计

    • 思路:01-设备ID-时间,

    • 将各个设备采集的数据均匀保存到不同分区,

      • 如果只是保存数据,读取时不考虑时序性,还可以将同一设备的数据均匀保存到不同分区,但查询难度加大,且只是分区内有有序,全局无序。
      • 考虑到需要按时间进行查询,保证同一设备数据在同一分区。
    • String iotID ;
      long time = System.currentTimeMillis();
      int region=Math.abs((iotID).hashCode())%10;
      String rowkey = "0" + region+ '.'+ time + "." + iot	ID;
      
  • 建表 预分区:

    • 分区键:01| ~ XX|;
    • 分区算法:(设备ID*时间)% XX
    • create 'test03','fdata',SPLITS => ['00|','01|','02|','03|','04|','05|','06|','07|','08|']
  • 对测试表设计rowkey与预分区后,测试表实现了负载均衡,如下图所示:
    HBase优化_第4张图片

5、查询问题

  • 由于通过rowkey设计与预分区后,IOT表的rowkey,在时间戳+设备ID前多加了具体的分区后,查询发生变化

  • 每次查询时,可根据分区策略,反推出分区号,在组合形成新的rowkey,在进行查询。

public static String RK(String uid,String date) throws ParseException {
        String Time = dateToStamp(date);
        int reg = Math.abs((uid).hashCode()) % 10;
        String rk = "0" + reg + '.' + Time + "." + uid;
        return rk;
    }
  • 对于hbase查询:

    • hbase的rowkey按照字典形式保存,通过rowkey查相应数据最快,因此一般将重要信息设计在rowkey中。

    • hbase的filler过滤查询时,如果指定rowkey范围,会进行全表查询,因此设计rowkey时,将时间戳包含在内。

    • Scan scan = new Scan();//若没有指定startRow以及stopRow,则全表扫描

        //扫描指定列族
        scan.addFamily("fdata".getBytes());
        //扫描指定的列
        scan.addColumn("fdata".getBytes(), column.getBytes());
    
        //指定扫描的行键范围, 前闭后开
        scan.setStartRow(RK(iotID,startTime).getBytes());
        scan.setStopRow(RK(iotID,endTime).getBytes());
    
        //设置每批次返回客户端的数据条数
        // scan.setBatch(20);
    
        //从cacheBlock中读取数据
        scan.setCacheBlocks(true);
        //  scan.setMaxResultSize(4);
        //  scan.setMaxVersions(2);//获取历史2个版本
    
            //多维过滤器
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
    
        //       //行键过滤  查询00开头的行键
        PrefixFilter prefixFilter = new PrefixFilter("00.".getBytes());
        filterList.addFilter(prefixFilter);
    
        //  正则行键过滤
       Filter Rowfilter = new RowFilter(CompareFilter.CompareOp.EQUAL,new RegexStringComparator(".*"+iotID));
       // filterList.addFilter(Rowfilter);
    
        //  查询 diviceid = “XXX”的某一行
         SingleColumnValueFilter deviceid1 = new SingleColumnValueFilter("fdata".getBytes(), "deviceid".getBytes(), CompareFilter.CompareOp.EQUAL, iotID.getBytes());
        filterList.addFilter(deviceid1);
    
        scan.setFilter(filterList);
    
        //通过getScanner查询获取到了表里面所有的数据,是多条数据
        ResultScanner scanner = table.getScanner(scan);
        //遍历ResultScanner 得到每一条数据,每一条数据都是封装在result对象里面了
    

6、数据删除

  • 1、试用用户IOT表

    • 对于一定的试用用户,系统自动为其建立一张表,
    • 虽然有可能未存入数据,但建表时hbase会分出一个region分区,但试用用户增多后,hbase分区数量也会增多,导致,
    • 可以通过设置hbase表的存活周期属性(TTL),若试用期到达后,自动删表,转为正式后可将数据迁入正式表。
  • 2、正式用户IOT表

    • 通过编写相关shell脚本,定时执行删除一定数据。

二、HBase优化策略

1、 HBase 客户端优化

1.1 Scan操作的缓存优化
  • 通常来讲一次scan会返回大量数据,因此客户端发起一次scan请求,实际并不会一次就将所有数据加载到本地,而是分成多次RPC请求进行加载,
  • 这样设计一方面是因为大量数据请求可能会导致网络带宽严重消耗进而影响其他业务,另一方面也有可能因为数据量太大导致本地客户端发生OOM。在这样的设计体系下用户会首先加载一部分数据到本地,然后遍历处理,再加载下一部分数据到本地处理,如此往复,直至所有数据都加载完成。数据加载到本地就存放在scan缓存中,默认100条数据大小。
  • 一般情况下,可能100条缓存数量就够了,但是遇到啊一些比较大的scan请求,可能查询几万或者10几万,那么缓存的命中率就很低了
  • 若scan请求很大,已经过万了,hbase.client.scanner.caching这个参数设置成500或者1000。
1.2 Get请求优化
  • HBase分别提供了单条get以及批量get的API接口,使用批量get接口可以减少客户端到HRegionServer之间的RPC连接数,提高读取性能。
  • 另外需要注意的是,批量get请求要么成功返回所有请求数据,要么抛出异常。
  • 使用get查询数据时,使用批量get[table.get(List),进行读取请求
1.3 指定显示列簇或者列
  • 不同列族的数据分开存储在不同的目录下。如果一个表有多个列族,只是根据Rowkey而不指定列族进行检索的话不同列族的数据需要独立进行检索,性能必然会比指定列族的查询差很多,很多情况下甚至会有2倍~3倍的性能损失,

  • 在查询的时候指定列簇或者列进行精确的查找

	 //扫描指定列族
    scan.addFamily("fdata".getBytes());
    //扫描指定的列
    scan.addColumn("fdata".getBytes(), column.getBytes());
1.4 离线读取设置禁止缓存
  • 通常,离线批量读取数据时,会进行一次性全表扫描,一方面数据量很大,另一方面请求只会执行一次。
  • 这种场景下如果使用scan默认设置,就会将数据从HDFS加载出来之后放到缓存。可想而知,大量数据进入缓存必将其他实时业务热点数据挤出,其他业务不得不从HDFS加载,进而会造成明显的读延迟毛刺。
  • 离线批量读取请求时,设置禁用缓存,scan.setBlockCache(false)

2、HBase服务器端优化

​ 一般服务端端问题一旦导致业务读请求延迟较大的话,通常是集群级别的,即整个集群的业务都会反映读延迟较大。

可以从4个方面入手:

2.1 负载均衡优化
  • 极端情况下,假如所有的读请求都落在一台RegionServer的某几个Region上,那么首先会造成该RegionServer资源严重消耗,
  • 另外不能发挥集群的并发处理能力,落在该台RegionServer上的其他业务会因此受到很大的波及,读请求不均衡不仅会造成本身业务性能很差,还会严重影响其他业务。
  • 当然,写请求不均衡也会造成类似的问题,可见负载不均衡是HBase的大忌。
  • 如果存在存在读请求不均衡现象,则RowKey必须进行散列化处理(比如MD5散列),同时建表必须进行预分区处理
2.2 BlockCache优化
  • 默认情况下,BlockCache和Memstore的配置相对比较均衡(各占40%),可以根据集群业务进行修正,

    • 读多写少业务,可以将BlockCache占比调大。
  • 另一方面,BlockCache的策略选择也很重要,不同策略对读性能来说影响并不是很大,但是对GC的影响却相当显著,尤其BucketCache的offheap模式下GC表现很优越。另外,HBase 2.0对offheap的改造(HBASE-11425)将会使HBase的读性能得到2~4倍的提升,同时GC表现会更好!

  • 所以建议观察所有RegionServer的缓存未命中率、配置文件相关配置项一级GC日志,确认BlockCache是否可以优化。如果缓存命中较低,建议使用offheap模式;

  • JVM内存配置量 < 20G,BlockCache策略选择LRUBlockCache;否则选择BucketCache策略的offheap模式

2.3 HFile文件优化
  • 一个store可能包含很多的HFile文件,文件越多,检索所需的IO次数必然越多,读取延迟也就越高。

  • 文件数量通常取决于Compaction的执行策略,一般和两个配置参数有关:hbase.hstore.compactionThresholdhbase.hstore.compaction.max.size

  • 前者表示一个store中的文件数超过多少就应该进行合并,后者表示参数合并的文件大小最大是多少,超过此大小的文件不能参与合并。

  • 这两个参数不能设置太’松’(前者不能设置太大,后者不能设置太小),导致Compaction合并文件的实际效果不明显,进而很多文件得不到合并。这样就会导致HFile文件数变多。

  • 所以建议观察RegionServer级别以及Region级别的storefile数,确认HFile文件是否过多,hbase.hstore.compactionThreshold设置不能太大,默认是3个;设置需要根据Region大小确定,

  • 通常可以简单的认为hbase.hstore.compaction.max.size= RegionSize / hbase.hstore.compactionThreshold

2.4 合并优化
  • Compaction是将小文件合并为大文件,提高后续业务随机读性能,但是也会带来IO放大以及带宽消耗问题(数据远程读取以及三副本写入都会消耗系统带宽)。

  • 正常配置情况下Minor Compaction并不会带来很大的系统资源消耗,除非因为配置不合理导致Minor Compaction太过频繁,或者Region设置太大情况下发生Major Compaction。

  • 观察系统IO资源以及带宽资源使用情况,再观察Compaction队列长度,确认是否由于Compaction导致系统资源消耗过多

  • Minor Compaction设置:hbase.hstore.compactionThreshold设置不能太小,又不能设置太大,因此建议设置为5~6;

  • Major Compaction设置:大Region读延迟敏感业务( 100G以上)通常不建议开启自动MajorCompaction,手动低峰期触发。小Region或者延迟不敏感业务可以开启Major Compaction,但建议限制流量

3、HBase 列簇设计优化

  • Bloomfilter主要用来过滤,不存在待检索RowKey或者Row-Col的HFile文件,避免无用的IO操作。
    • 它会告诉你在这个HFile文件中是否可能存在待检索的KV,如果不存在,就可以不用消耗IO打开文件进行seek。
    • 很显然,通过设置Bloomfilter可以提升随机读写的性能。
  • Bloomfilter取值有两个,row以及rowcol,需要根据业务来确定具体使用哪种。
    • 如果业务大多数随机查询仅仅使用row作为查询条件,Bloomfilter一定要设置为row,
    • 否则如果大多数随机查询使用row+cf作为查询条件,Bloomfilter需要设置为rowcol。
    • 如果不确定业务查询类型,设置为row。
  • 任何业务都应该设置Bloomfilter,通常设置为row就可以,除非确认业务随机查询类型为row+cf,可以设置为rowcol

4、HDFS 相关优化

HDFS作为HBase最终数据存储系统,通常会使用三副本策略存储HBase数据文件以及日志文件。

从HDFS的角度望上层看,HBase即是它的客户端,HBase通过调用它的客户端进行数据读写操作,因此HDFS的相关优化也会影响HBase的读写性能。

这里主要关注如下三个方面:

4.1 Short-CircuitLocal Read功能是否开启
  • HDFS读取数据,都需要经过DataNode,
    • 客户端会向DataNode发送读取数据的请求,DataNode接受到请求之后从硬盘中将文件读出来,再通过TPC发送给客户端。
    • Short Circuit策略,允许客户端绕过DataNode直接读取本地数据。可参考
  • 所以建议开启Short Circuit Local Read功能,可以参考
4.2 HedgedRead功能是否开启
  • HBase数据在HDFS中一般都会存储三份,而且优先会通过Short-Circuit Local Read功能尝试本地读。
  • 但是在某些特殊情况下,有可能会出现因为磁盘问题或者网络问题引起的短时间本地读取失败,为了应对这类问题,社区开发者提出了补偿重试机制 – Hedged Read。
    • 该机制基本工作原理为:客户端发起一个本地读,一旦一段时间之后还没有返回,客户端将会向其他DataNode发送相同数据的请求。哪一个请求先返回,另一个就会被丢弃。
  • 所以建议开启Hedged Read功能,具体参考
4.3数据本地率是否太低
  • 数据本地率:HDFS数据通常存储三份,

    • 假如当前RegionA处于Node1上,数据a写入的时候三副本为(Node1,Node2,Node3),数据b写入三副本是(Node1,Node4,Node5),数据c写入三副本(Node1,Node3,Node5),可以看出来所有数据写入本地Node1肯定会写一份,数据都在本地可以读到,因此数据本地率是100%。现在假设RegionA被迁移到了Node2上,只有数据a在该节点上,其他数据(b和c)读取只能远程跨节点读,本地率就为33%(假设a,b和c的数据大小相同)。
  • 据本地率太低,会产生大量的跨网络IO请求,必然会导致读请求延迟较高,因此提高数据本地率可以有效优化随机读性能。

    • 数据本地率低的原因一般是因为Region迁移(自动balance开启、RegionServer宕机迁移、手动迁移等),
    • 因此,一方面,可以通过避免Region无故迁移来保持数据本地率,
    • 另一方面,如果数据本地率很低,也可以通过执行major_compact提升数据本地率到100%
  • 所以避免Region无故迁移,比如关闭自动balance、RS宕机及时拉起并迁回飘走的Region等;在业务低峰期执行major_compact提升数据本地率

三、Hbase参数配置

1、phenix创建二级索引出错

问题

修改hbase-site.xml

hbase.regionserver.wal.codec org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec

2、hbase读写大量数据时,client连接超时

问题

zk最大连接数过小,默认值是300,在查询量与记录数量特大的集群中,可能会造成相互间通信连接过多从而拒绝连接服务。

修改hbase-site.xml

hbase.zookeeper.property.maxClientCnxns 15000

hbase内存堆大小设置太小,修改hbase-env.sh文件,把堆大小设置大一些。默认1000m

export HBASE_HEAPSIZE=30720

3、服务器region太多

  • 一个RegionServer上有n个region,按照一个表中start rowkey与end rowkey 划分为一个region。Region合理,负载均衡,各RegionServer平均分担的Region。如果region太多,超出此内存(memstore使用率过高),可能会导致无响应服务器或压缩风暴。

  • Region的最大数量设置,主要由memstore内存使用量决定,计算集群region数量的公式:

    • ((RS Xmx) * hbase.regionserver.global.memstore.size) / (hbase.hregion.memstore.flush.size * (# column families))
  • 假设一个RS有16GB内存,那么16384*0.4/128m 等于51个活跃的region。如果写很重的场景下,可以适当调高hbase.regionserver.global.memstore.size,这样可以容纳更多的region数量。参考:Hbase官方文档

region太多,可能由于本身所建立的表太多,以及一些表分区太多。

  • region合并

    • 不是为了性能, 而是出于维护的目的 .
    • 在线进行合并:merge_region 'c2212a3956b814a6f0d57a90983a8515','553dd4db667814cf2f050561167ca030'
  • 删除一些测试表

    • disable ‘user’
    • drop ‘user’
    • merge_region ‘ada230b1bbc505b193d1a7553674d23a’, ‘dd716bd5e4b0a4a3eb1951d9e722db8d’

4、Scan缓存设置

  • 数据加载到本地就存放在scan缓存中,默认100条数据大小。一般情况下,可能100条缓存数量就够了,但是遇到啊一些比较大的scan请求,可能查询几万或者10几万,那么缓存的命中率就很低了,

    • 修改hbase-env.sh文件中,hbase.client.scanner.caching=500或者100

5、region大小设置

  • hbase.hregion.max.filesize比较小时,触发split的机率更大,系统的整体访问服务会出现不稳定现象。

  • hbase.hregion.max.filesize比较大时,由于长期得不到split,同一个region内发生多次compaction的机会增加,也会降低系统的性能、稳定性,因此平均吞吐量会受到一些影响而下降。

    • 修改hbase-env.sh文件中,hbase.hregion.max.filesize=5-10GB
  • 关闭某些重要场景的HBase表的major_compact,在非高峰期的时候再去调用major_compact,这样可以减少split的同时,显著提供集群的性能,吞吐量、非常有用。通过HBase的UI控制台都可以监控到region的数量&大小指标。

6、memstore大小设置

  • 一个RegionServer上有n个region,每个region会根据不同的列族数,拥有不同的store,每个store有一块自己的memstore内存区和多个HFile文件。RegionServer将总内存的一小部分专用于memstore存储。每个region都有自己的memstore,memstore大小可配置,通常在128-256 MB范围内,

  • HBase中数据一开始会写入memstore,满128MB(默认)以后,会flush到disk上而成为storefile。当storefile数量超过触发因子时,会启动compaction过程将它们合并为一个storefile,对集群的性能有一定影响。而当合并后的storefile大于max.filesize,会触发分割动作,将它切分成两个region。

    • 修改hbase-env.sh文件中:
      • hbase.hregion.memstore.flush.size。
      • hbase.regionserver.global.memstore.size

7、BlockCache设置

  • 默认情况下,BlockCache和Memstore的配置相对比较均衡(各占40%),可以根据集群业务进行修正,比如读多写少业务可以将BlockCache占比调大
    • 修改hbase-env.sh文件中:
      • VM内存配置量 < 20G,BlockCache策略选择LRUBlockCache
      • 否则,选择BucketCache策略的offheap模式

8、HFile文件设置

  • 一个store可能包含很多的HFile文件,越多检索所需的IO次数必然越多,读取延迟也就越高。

  • HFile文件数量,通常取决于Compaction的执行策略,一般和两个配置参数有关:hbase.hstore.compactionThreshold(store中的文件数超过多少就应该进行合并)和hbase.hstore.compaction.max.size(参数合并的文件大小最大是多少,超过此大小的文件不能参与合并)。

  • 这两个参数不能设置太’松’(前者不能设置太大,后者不能设置太小),导致Compaction合并文件的实际效果不明显,进而很多文件得不到合并。这样就会导致HFile文件数变多。可观察RegionServer级别以及Region级别的storefile数,确认HFile文件是否过多,

  • 修改hbase-env.sh文件中: hbase.hstore.compactionThreshold默认是3个,建议设置为5~6;

  • Major Compaction设置:大Region读延迟敏感业务( 100G以上)通常不建议开启自动MajorCompaction,手动低峰期触发。小Region或者延迟不敏感业务可以开启Major Compaction,但建议限制流量

9、减少flush过程,提高IO吞吐量

  • autoflush=true虽然会让写入速度下降2-3倍,但是对于很多在线应用来说这都是必须打开的,也正是hbase为什么让它默认为true的原因,每次请求都会发往regionserver,而regionserver接收到请求后第一件事情就是写HLOG,因此对IO要求是非常高的,
  • 为了提高hbase的写入速度应该尽可能地提高IO吞吐量,比如增加磁盘、使用raid卡、减少replication因子数等。
  • 修改hbase-env.sh文件中:setAutoFlush=false

10、具体配置参数

  <property>
      <name>hbase.client.scanner.cachingname>
     
      <value>500value>
    property>
<property>
  <name>hbase.hregion.majorcompactionname>
  <value>604800000value>
property> 
<property>
  <name>hbase.hregion.majorcompaction.jittername>
  <value>0.50value>
property>
<property>
  <name>hbase.hregion.max.filesizename>
 
  <value>32212254720value>  
property>
<property>
  <name>hbase.hregion.memstore.flush.sizename>
  <value>134217728value>
property>
<property>
  <name>hbase.hstore.compactionThresholdname>
  
  <value>6value>
property>   
<property>
  <name>hbase.regionserver.handler.countname>
  
  <value>100value>
property>
<property>
  <name>hfile.block.cache.sizename>
  
  <value>0.5value>
property>
<property>
  <name>hbase.regionserver.global.memstore.sizename>
  <value>0.3value>
property>
<property>  
   <name>hbase.bucketcache.sizename>  
   <value>16384value> 
property>
 <property>
  <name>hbase.regionserver.wal.codecname>
    
  <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodecvalue>
property>

<property>
     <name>hbase.region.server.rpc.scheduler.factory.classname>
     <value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactoryvalue>
property>
<property>
		<name>hbase.rpc.controllerfactory.classname>
		<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactoryvalue>
property>
  <property>
    <name>hbase.table.sanity.checksname>
    <value>falsevalue>
property>

 <property>
<name>hbase.zookeeper.property.maxClientCnxnsname>
<value>15000value>
property>

四、HBase性能测试

本次测试,只是在本机虚拟机中进行,还未在服务器中测试。

1、测试工具选择

  • YCSB(Yahoo! Cloud Serving Benchmark)

    • YCSB是一款开源的分布式性能测试工具,常用于测试NoSQL产品的读写性能。
    • YCSB支持常见的NoSQL数据库和数据网格产品,如Cassandra、MongoDB、HBase、Redis、Infinispan等主流产品。YCSB不仅安装使用简单,还能自由扩展测试数据类型和支持的数据库产品
  • PE(PerformanceEvaluation),这里我们会使用YCSB,YCSB对比PE有点明显

    • 可任意设置压测的读写比例、线程数量,最后的测试报告也比较详细
    • 通过YCSB的测试数据报告比较具有说服力,完整。

2、YCSB工具使用

运行一个压力测试需要 6 步:

  1. 配置需要测试的数据库
  2. 选择合适的数据库接口层
  3. 选择合适的 workload
  4. 选择合适的运行时参数
  5. 装载数据(loading phase)
  6. 运行测试(transaction phase)

(1)下载YCSB包

登入YCSB github网,找到下载地址,这里我们选择最新版0.17,并往下拉找到hbase12的版本。
HBase优化_第5张图片

  • YCSB 命名规则均为NOSQL数据库名+’-binding’后缀。
  • 这些目录也即表示了YCSB支持的所有的NOSQL数据库类型,同时你也可以按照规范加入新的数据库类型。
  • 每个bindings目录内部都有lib子目录,用于存放YCSB对访问这些数据库所需要的一些jar包依赖。
  • 配置:
    • H B A S E H O M E / l i b 目 录 下 的 所 有 j a r 包 拷 贝 到 HBASE_HOME/lib目录下的所有jar包拷贝到 HBASEHOME/libjarYCSB_HOME/hbase10-binding/lib中(lib文件夹本身存在,直接进行复制拷贝即可),不必须。
    • 同时将 H B A S E H O M E / c o n f / h b a s e − s i t e . x m l 拷 贝 到 HBASE_HOME/conf/hbase-site.xml拷贝到 HBASEHOME/conf/hbasesite.xmlYCSB_HOME/hbase10-binding/conf中(conf文件夹自己创建),必须。

workload

Workload 定义了如何向数据库中加载测试数据,包括两个部分:

  • Workload Java 类(com.yahoo.ycsb.Workload 的子类)
  • 配置文件(Java Properties 格式)

YCSB 的 CoreWorkload 预置了一些标准测试数据,可以直接使用,包括 6 个不同的类型:

  1. Workload A:重更新,50% 读 50% 写,例如 session sotre

  2. Workload B:读多写少,95% 读 5% 写,例如 photo tagging

  3. Workload C:只读:100% 读,例如 user profile cache

  4. Workload D:读最近更新:这个 workload 会插入新纪录,越新的纪录读取概率越大,例如:user status updates

  5. Workload E:小范围查询:这个 workload 会查询小范围的纪录,而不是单个纪录,例如:threaded conversations

  6. Workload F:读取-修改-写入:这个 workload 会读取一个纪录,然后修改这个纪录,最后写回,例如:user database

可以根据测试需求选择合适的 workload,也可以新建一个新的 workload。

运行时参数

除了在 workload 中配置参数外,YCSB 还支持这些运行时参数:

  • threads:客户端线程数,默认为 1

  • target:每秒的目标操作数,默认为无限制(尽可能快地完成操作)。例如一个操作需要 100 ms,那么一个线程 1s 内可以完成 10 个操作,通过 -target 参数可以将操作放缓,控制在 10 个以下

  • s:每 10s 打印一次客户端状态,用于调试

3、本地虚拟机测试

(1)创建测试表

这里建议预分区的个数为 10 * RegionServers

n_splits = 12 # HBase recommends (10 * number of regionservers)
create 'usertable', 'cf', {SPLITS => (1..n_splits).map {|i| "user#{1000+i*(9999-1000)/n_splits}"}}

或直接:

create 'usertable', 'family'

(2)加载数据

./bin/ycsb load hbase12 -P workloads/workloada -p threads=10 -p table=usertable -p columnfamily=family -p recordcount=10000

或:
./bin/ycsb load hbase10 -P workloads/workloada -p threads=10 -p table=usertable -p columnfamily=family -p recordcount=10000 -s > logs/load.log
  • 参数解释如下:

  • load 表示这是一次加载数据操作;

  • hbase10指明了所用的数据库类型;

  • -P指明了所用的配置文件的路径;

  • -p 可以显示修改YCSB内置的默认配置,例如这里配置

  • recordcount=10000来覆盖之前说过的workloada中默认的recordcount=1000;

  • -s一次加载数据或执行测试的过程实践很长,YCSB客户端需要定时(默认10s)发送状态信息;

  • logs/load.log表示结果日志写入位置(若没有logs文件夹就自己新建一个,也可以不加此参数,则运行结果直接打印到屏幕上);

HBase优化_第6张图片

HBase优化_第7张图片

(3)执行测试

bin/ycsb run hbase12 -P workloads/workloada -threads 10 -p operationcount=1000 -p table=usertable -p columnfamily=family -p measurementtype=timeseries -p timeseries.granularity=2000 -s > logs/transaction-workloadAA.log
  • 参数解释如下:
  • -threads 10配置了并发线程个数
  • -p operationcount=1000000 覆盖了workloada operationcount=1000表示本次测试操作记录数为1000000
  • -p measurementtype=timeseries -p timeseries.granularity=2000指明了YCSB客户端多长时间汇总一次延时,timeseries.granularity属性值的单位为1000milliseconds。所以这里的配置就表示2000s记录一次本2000s的平均延时。

优化前:

HBase优化_第8张图片

优化后:

HBase优化_第9张图片

优化前 优化后
数据加载时间(毫秒) 10528 1379ms
平均并发量(每秒/条) 94.98 725.1613
read操作总数 524 506
每次read平均延时(微秒) 81067 4148.478
read操作最大延时(微秒) 1652 512
read操作最小延时(微秒) 5128191 89535

4、服务器测试

(1)建表

n_splits = 12 # HBase recommends (10 * number of regionservers)
create 'usertable', 'cf', {SPLITS => (1..n_splits).map {|i| "user#{1000+i*(9999-1000)/n_splits}"}}

(2)加载数据

./bin/ycsb load hbase10 -P workloads/workloada -p table=usertable -p columnfamily=cf -p recordcount=1000000 -p operationcount=1000000

HBase优化_第10张图片

HBase优化_第11张图片

(3)执行测试

./bin/ycsb run hbase10 -P workloads/workloada -p table=usertable -p columnfamily=cf -p recordcount=1000000 -p operationcount=1000000

HBase优化_第12张图片

你可能感兴趣的:(项目经验)