使用常用工具测试HBase应用

标签: 工具 测试 hbase | 发表时间:2013-11-19 16:47 | 作者:moxiaomomo
出处:http://blog.csdn.net

虽然业界采用Apache HBase来构建终端用户应用的范围越来越多,但是许多这种应用并没有经过良好的测试。通过这篇文章,你可以了解到有关这方面的一些容易实现的测试方法。

我们首先以 JUnit为例, 然后是 Mockito 和 Apache MRUnit, 接着会使用HBase的一个微型集群来做集成测试。(HBase自身的代码也是通过一个微型的集群来测试的, 所以对于上游的应用为什么不能这样测试呢?)

作为探讨的基础,我们假设你创建了用于将数据插入到HBase 的数据访问对象(DAO)。实际的逻辑可能很复杂,但为了演示用例,以下简单的代码也可以完成基本的功能:

public class MyHBaseDAO {

                public static void insertRecord(HTableInterface table, HBaseTestObj obj)
        throws Exception {
                        Put put = createPut(obj);
                        table.put(put);
                }

                private static Put createPut(HBaseTestObj obj) {
                        Put put = new Put(Bytes.toBytes(obj.getRowKey()));
                        put.add(Bytes.toBytes("CF"), Bytes.toBytes("CQ-1"),
                                Bytes.toBytes(obj.getData1()));
                        put.add(Bytes.toBytes("CF"), Bytes.toBytes("CQ-2"),
                                Bytes.toBytes(obj.getData2()));
                        return put;
                }
}

 

HBaseTestObj是一个含有成员rowkey, data1, and data2及其getter和setter的对象。

方法insertRecord向HBase表插入了列族为CF, 列为CQ-1,CQ-2的记录。方法createPut 简单的包装了Put数据并返回给调用者。

使用JUnit

对于大部分Java开发者来说都很熟悉的JUnit, 可以容易的应用到HBase大部分程序中。 首先,在pom中添加依赖库:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

 

然后在测试类中使用:

public class TestMyHbaseDAOData {
                @Test
                public void testCreatePut() throws Exception {
                HBaseTestObj obj = new HBaseTestObj();
                obj.setRowKey("ROWKEY-1");
                obj.setData1("DATA-1");
                obj.setData2("DATA-2");
                Put put = MyHBaseDAO.createPut(obj);
                assertEquals(obj.getRowKey(), Bytes.toString(put.getRow()));
                assertEquals(obj.getData1(), Bytes.toString(put.get(Bytes.toBytes("CF"),
  Bytes.toBytes("CQ-1")).get(0).getValue()));
                assertEquals(obj.getData2(), Bytes.toString(put.get(Bytes.toBytes("CF"),
  Bytes.toBytes("CQ-2")).get(0).getValue()));
                }
  }

 

上面所写的代码就是为了保证方法createPut能正常的创建,填充,和返回对象Put。

使用Mockito

怎么实现像JUnit那样的功能来测试方法insertRecord? 使用Mockito可以这样做:

首先在pom中添加Mockito依赖库:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

 

然后在测试类中增加如下代码:

@RunWith(MockitoJUnitRunner.class)
public class TestMyHBaseDAO{
  @Mock 
  private HTableInterface table;
  @Mock
  private HTablePool hTablePool;
  @Captor
  private ArgumentCaptor putCaptor;

  @Test
  public void testInsertRecord() throws Exception {
    //return mock table when getTable is called
    when(hTablePool.getTable("tablename")).thenReturn(table);
    //create test object and make a call to the DAO that needs testing
    HBaseTestObj obj = new HBaseTestObj();
    obj.setRowKey("ROWKEY-1");
    obj.setData1("DATA-1");
    obj.setData2("DATA-2");
    MyHBaseDAO.insertRecord(table, obj);
    verify(table).put(putCaptor.capture());
    Put put = putCaptor.getValue();
  
    assertEquals(Bytes.toString(put.getRow()), obj.getRowKey());
    assert(put.has(Bytes.toBytes("CF"), Bytes.toBytes("CQ-1")));
    assert(put.has(Bytes.toBytes("CF"), Bytes.toBytes("CQ-2")));
    assertEquals(Bytes.toString(put.get(Bytes.toBytes("CF"),
Bytes.toBytes("CQ-1")).get(0).getValue()), "DATA-1");
    assertEquals(Bytes.toString(put.get(Bytes.toBytes("CF"),
Bytes.toBytes("CQ-2")).get(0).getValue()), "DATA-2");
  }
}

 

上述代码使用了“ROWKEY-1”, “DATA-1”, “DATA-2”来填充了HBaseTestObj,然后用table接口和DAO来将它插入到表中。此过程将捕捉DAO用来inert操作的对象Put和检查rowkey, data1及 data2的值是否符合期望。

这里的重点是需要管理HTable pool和在DAO之外创建的HTable对象。这样会让你清晰的进行mock(创建虚拟对象)并像上面一样测试Put对象。近似的也可以这样测试Get, Scan, Delete等操作。

使用MRUnit

使用常规的数据访问来覆盖单元测试,让我们针对HBase表来实现MapReduce作业。

可以像测试MapReduce常规任务来测试HBase的MapReduce作业,MRUnit使得很容易完成这样的单元测试。

假设你有一个往HBase表写数据MR作业“MyTest”, 它的列族为“CF”。作业的reducer部分像以下这样:

  
public class MyReducer extends TableReducer<Text, Text, ImmutableBytesWritable> {
   public static final byte[] CF = "CF".getBytes();
   public static final byte[] QUALIFIER = "CQ-1".getBytes();
  public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
     //bunch of processing to extract data to be inserted, in our case, lets say we are simply
     //appending all the records we receive from the mapper for this particular
     //key and insert one record into HBase
     StringBuffer data = new StringBuffer();
     Put put = new Put(Bytes.toBytes(key.toString()));
     for (Text val : values) {
         data = data.append(val);
     }
     put.add(CF, QUALIFIER, Bytes.toBytes(data.toString()));
     //write to HBase
     context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())), put);
   }
 }

 

现在你如何在MRUnit中使用单元测试来测试reducer呢? 首先,在pom中添加MRUnit依赖库.

<dependency>
   <groupId>org.apache.mrunit</groupId>
   <artifactId>mrunit</artifactId>
   <version>1.0.0 </version>
   <scope>test</scope>
</dependency>

 

 

接着,在测试类中像下面这样调用MRUnit提供的ReduceDriver:

public class MyReducerTest {
    ReduceDriver<Text, Text, ImmutableBytesWritable, Writable> reduceDriver;
    byte[] CF = "CF".getBytes();
    byte[] QUALIFIER = "CQ-1".getBytes();

    @Before
    public void setUp() {
      MyReducer reducer = new MyReducer();
      reduceDriver = ReduceDriver.newReduceDriver(reducer);
    }
  
   @Test
   public void testHBaseInsert() throws IOException {
      String strKey = "RowKey-1", strValue = "DATA", strValue1 = "DATA1", 
strValue2 = "DATA2";
      List<Text> list = new ArrayList<Text>();
      list.add(new Text(strValue));
      list.add(new Text(strValue1));
      list.add(new Text(strValue2));
      //since in our case all that the reducer is doing is appending the records that the mapper   
      //sends it, we should get the following back
      String expectedOutput = strValue + strValue1 + strValue2;
     //Setup Input, mimic what mapper would have passed
      //to the reducer and run test
      reduceDriver.withInput(new Text(strKey), list);
      //run the reducer and get its output
      List<Pair<ImmutableBytesWritable, Writable>> result = reduceDriver.run();
    
      //extract key from result and verify
      assertEquals(Bytes.toString(result.get(0).getFirst().get()), strKey);
    
      //extract value for CF/QUALIFIER and verify
      Put a = (Put)result.get(0).getSecond();
      String c = Bytes.toString(a.get(CF, QUALIFIER).get(0).getValue());
      assertEquals(expectedOutput,c );
   }

}

 

在MyReducer中进行的一系列过程,你会验证:

 

  • 你所期望得到的输出结果。
  • 对象Put以 “RowKey-1″为键插入到HBAse表中。
  • “DATADATA1DATA2″是列族CF和列CQ的值。

 

你也可以类似的使用MapperDriver来测试从HBase中获取数据的Mapper,或者测试从HBase读取、处理和写入数据到HDFS的MR作业。

使用HBase Mini-cluster

现在我们来看一下怎样实现集成测试。HBase附带了HBaseTestingUtility, 这个用于在简单的mini-cluster环境中编写集成测试。为了引用正确的库,在pom中需要添加如下依赖:

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.0.0-cdh4.2.0</version>
    <type>test-jar</type>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase</artifactId>
    <version>0.94.2-cdh4.2.0</version>
    <type>test-jar</type>
    <scope>test</scope>
</dependency>
        
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs</artifactId>
    <version>2.0.0-cdh4.2.0</version>
    <type>test-jar</type>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs</artifactId>
    <version>2.0.0-cdh4.2.0</version>
    <scope>test</scope>
</dependency>

 

现在看一下怎样来为MyDAO的插入操作运行一个集成测试:

public class MyHBaseIntegrationTest {
private static HBaseTestingUtility utility;
byte[] CF = "CF".getBytes();
byte[] QUALIFIER = "CQ-1".getBytes();

@Before
public void setup() throws Exception {
        utility = new HBaseTestingUtility();
        utility.startMiniCluster();
}

@Test
    public void testInsert() throws Exception {
         HTableInterface table = utility.createTable(Bytes.toBytes("MyTest"),
                         Bytes.toBytes("CF"));
         HBaseTestObj obj = new HBaseTestObj();
         obj.setRowKey("ROWKEY-1");
         obj.setData1("DATA-1");
         obj.setData2("DATA-2");
         MyHBaseDAO.insertRecord(table, obj);
         Get get1 = new Get(Bytes.toBytes(obj.getRowKey()));
         get1.addColumn(CF, CQ1);
         Result result1 = table.get(get1);
         assertEquals(Bytes.toString(result1.getRow()), obj.getRowKey());
         assertEquals(Bytes.toString(result1.value()), obj.getData1());
         Get get2 = new Get(Bytes.toBytes(obj.getRowKey()));
         get2.addColumn(CF, CQ2);
         Result result2 = table.get(get2);
         assertEquals(Bytes.toString(result2.getRow()), obj.getRowKey());
         assertEquals(Bytes.toString(result2.value()), obj.getData2());
    }}

 

上面代码创建了一个HBase微型集群并启动它,然后创建了名为“MyTest”的其列族为"CF"的HBase表,接着使用DAO插入一条记录、再从该表执行Get操作,验证DAO是否正确的插入记录。

同样可以测试更加复杂的MR作业。也可以在创建HBase集群,运行MR作业,输出数据到HBase表,验证插入的数据时访问HDFS及ZooKeeper mini-cluster。

注意:启动一个mini-cluster需要20到30秒,在Windows下需要安装Cygwin。然而它们应该只是周期性的运行,更长的时间也是可以接受的。 

可参考 https://github.com/sitaula/HBaseTest,上面有同样的示例代码。Happy testing!


原文: How-to: Test HBase Applications Using Popular Tools

作者:moxiaomomo 发表于2013-11-19 8:47:30 原文链接
阅读:122 评论:0 查看评论

相关 [工具 测试 hbase] 推荐:

使用常用工具测试HBase应用

- - CSDN博客云计算推荐文章
虽然业界采用Apache HBase来构建终端用户应用的范围越来越多,但是许多这种应用并没有经过良好的测试. 通过这篇文章,你可以了解到有关这方面的一些容易实现的测试方法. 我们首先以 JUnit为例, 然后是 Mockito 和 Apache MRUnit, 接着会使用HBase的一个微型集群来做集成测试.

HBase随机读写性能测试

- jiaosq - NoSQLFan
本文转载自淘宝网BlueDavy同学的博客,文章基于淘宝对HBase的大量应用,给出了一个HBase的随机读写性能测试结果,对测试环境、配置及性能参数分析都有较详细的描述,推荐给各位NoSQL Fans. 根据最近生产环境使用的经验,更多的项目的采用,以及采用了更加自动的测试平台,对HBase做了更多的场景的测试,在这篇blog中来分享下纯粹的随机写和随机读的性能数据,同时也分享下我们调整过后的参数.

[原]hbase测试压缩效果报告

- - 分布式应用与服务器架构专栏
测试需求,就是将hbase里的表,按照不同的压缩方式(因不支持bz,所以没有bz的测试结果),进行保存,以下是对比结果:. snappy和lzo都不太适合在hbase里用压缩. 后面进行了一个比较特殊的测试. 就是原始数据有43个columns,如果了解其存储原理的话,那么占用的空间是很大的. 我采用了合并这个43个column变成一个(注:这里考虑合并是因为有业务的需要).

HBase随机写以及随机读性能测试

- d0ngd0ng - BlueDavy之技术blog
根据最近生产环境使用的经验,更多的项目的采用,以及采用了更加自动的测试平台,对HBase做了更多的场景的测试,在这篇blog中来分享下纯粹的随机写和随机读的性能数据,同时也分享下我们调整过后的参数. 1、Region Server: 5台,12块1T SATA盘(7200 RPM),No Raid,物理内存24G,CPU型号为E5620;.

基于Solr的HBase多条件查询测试

- - 互联网 - ITeye博客
某电信项目中采用HBase来存储用户终端明细数据,供前台页面即时查询. HBase无可置疑拥有其优势,但其本身只对rowkey支持毫秒级 的快 速检索,对于多字段的组合查询却无能为力. 针对HBase的多条件查询也有多种方案,但是这些方案要么太复杂,要么效率太低,本文只对基于Solr的 HBase多条件查询方案进行测试和验证.

性能测试工具 CBenchmark

- lele - 开源中国社区最新软件
CBenchmark—-CharlesCui’s Benchmark 这是我实现的一款性能测试工具,之前在工作中常用LoadRunner之类的工具来完成性能测试,但受限于LR极其昂贵的Lisence以及难以定制的SDK,于是我用C/C++实现了这个工具,并借助Linux系统对线程和进程的良好调度,可以实现极高的并发压力.

压力测试工具Benchmark

- - 企业架构 - ITeye博客
已有 0 人发表留言,猛击->> 这里<<-参与讨论. —软件人才免语言低担保 赴美带薪读研.

hbase介绍

- AreYouOK? - 淘宝数据平台与产品部官方博客 tbdata.org
hbase是bigtable的开源山寨版本. 是建立的hdfs之上,提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统. 它介于nosql和RDBMS之间,仅能通过主键(row key)和主键的range来检索数据,仅支持单行事务(可通过hive支持来实现多表join等复杂操作). 主要用来存储非结构化和半结构化的松散数据.

Riak对比HBase

- - NoSQLFan
文章来自 Riak官方wiki,是一篇Riak与HBase的对比文章. Riak官方的对比通常都做得很中肯,并不刻意偏向自家产品. 对比的Riak版本是1.1.x,HBase是0.94.x. Riak 与 HBase 都是基于 Apache 2.0 licensed 发布. Riak 的实现是基于 Amazon 的 Dynamo 论文,HBase 是基于 Google 的 BigTable.

[转]HBase简介

- - 小鸥的博客
   Hbase是一个分布式开源数据库,基于Hadoop分布式文件系统,模仿并提供了基于Google文件系统的Bigtable数据库的所有功能. 其目标是处理非常庞大的表,可以用普通的计算机处理超过10亿行数据,并且有数百万列元素组成的数据表. Hbase可以直接使用本地文件系统或者Hadoop作为数据存储方式,不过为了提高数据可靠性和系统的健壮性,发挥Hbase处理大数据量等功能,需要使用Hadoop作为文件系统.