HBase
 sql >> Base de Dados >  >> NoSQL >> HBase

Como fazer:testar aplicativos HBase usando ferramentas populares


Embora a adoção do Apache HBase para a criação de aplicativos de usuário final tenha disparado, muitos desses aplicativos (e muitos aplicativos em geral) não foram bem testados. Neste post, você aprenderá algumas das maneiras pelas quais esse teste pode ser feito facilmente.

Começaremos com o teste de unidade via JUnit, depois passaremos para o uso do Mockito e do Apache MRUnit e, em seguida, para o uso de um mini-cluster HBase para teste de integração. (A própria base de código do HBase é testada por meio de um mini-cluster, então por que não aproveitar isso para aplicativos upstream também?)

Como base para discussão, vamos supor que você tenha um objeto de acesso a dados HBase (DAO) que faz a seguinte inserção no HBase. A lógica poderia ser mais complicada, é claro, mas por uma questão de exemplo, isso faz o trabalho.
public class MyHBaseDAO { public static void insertRecord(HTableInterface table, HBaseTestObj obj) lança Exception { Put put =createPut(obj); tabela.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())); retorno posto; }}



HBaseTestObj é um objeto de dados básico com getters e setters para rowkey, data1 e data2.

O insertRecord faz uma inserção na tabela HBase na família de colunas de CF, com CQ-1 e CQ-2 como qualificadores. O método createPut simplesmente preenche um Put e o retorna ao método de chamada.

Usando JUnit


JUnit, que é bem conhecido pela maioria dos desenvolvedores Java neste momento, é facilmente aplicado a muitos aplicativos HBase. Primeiro, adicione a dependência ao seu pom:
 junit   junit   4.11   teste



Agora, dentro da classe de teste:
classe pública TestMyHbaseDAOData { @Test public void testCreatePut() lança exceção { 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())); } }



O que você fez aqui foi garantir que seu método createPut criasse, preenchesse e retornasse um objeto Put com valores esperados.

Usando o Mockito


Então, como você faz o teste de unidade do método insertRecord acima? Uma abordagem muito eficaz é fazê-lo com Mockito.

Primeiro, adicione o Mockito como uma dependência ao seu pom:
   org.mockito   mockito-all   1.9.5 teste 


Então, na classe de teste:
@RunWith(MockitoJUnitRunner.class)classe pública TestMyHBaseDAO{  @Mock   tabela HTableInterface privada; @Mock  HTablePool privado hTablePool; @Captor privado ArgumentCaptor putCaptor; @Test  public void testInsertRecord() throws Exception {    //retorna a tabela simulada quando getTable é chamado    when(hTablePool.getTable("tablename")).thenReturn(table); //cria o objeto de teste e faz uma chamada para o DAO que precisa ser testado    HBaseTestObj obj =new HBaseTestObj(); obj.setRowKey("ROWKEY-1"); obj.setData1("DATA-1"); obj.setData2("DATA-2"); MyHBaseDAO.insertRecord(tabela, obj); verifique(tabela).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"); }}



Aqui você preencheu HBaseTestObj com “ROWKEY-1”, “DATA-1”, “DATA-2” como valores. Em seguida, você usou a tabela simulada e o DAO para inserir o registro. Você capturou o Put que o DAO teria inserido e verificou se rowkey, data1 e data2 são o que você espera que sejam.

A chave aqui é gerenciar o pool htable e a criação de instância htable fora do DAO. Isso permite que você zombe deles de forma limpa e teste Puts como mostrado acima. Da mesma forma, agora você pode expandir para todas as outras operações, como Obter, Verificar, Excluir e assim por diante.

Usando MRUnit


Com os testes regulares de unidade de acesso a dados cobertos, vamos nos voltar para os trabalhos MapReduce que vão contra as tabelas HBase.

Testar trabalhos de MR que vão contra o HBase é tão simples quanto testar trabalhos regulares do MapReduce. O MRUnit facilita muito o teste de trabalhos MapReduce, incluindo os de HBase.

Imagine que você tenha um trabalho de MR que grava em uma tabela HBase, “MyTest”, que tem uma família de colunas, “CF”. O redutor de tal trabalho pode se parecer com:
classe pública MyReducer extends TableReducer { public static final byte[] CF ="CF".getBytes(); public static final byte[] QUALIFIER ="CQ-1".getBytes(); public void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException { //bando de processamento para extrair dados a serem inseridos, no nosso caso, digamos que estamos simplesmente //anexando todos os registros que recebemos do mapeador para esta //chave específica e insira um registro no HBase StringBuffer data =new StringBuffer(); Put put =new Put(Bytes.toBytes(key.toString())); for (Texto val :valores) { data =data.append(val); } put.add(CF, QUALIFICADOR, Bytes.toBytes(data.toString())); //gravar no HBase context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())), put); } }



Agora, como você faz o teste de unidade do redutor acima no MRUnit? Primeiro, adicione o MRUnit como uma dependência ao seu pom.
 org.apache.mrunit mrunit 1.0.0  teste 




Então, dentro da classe de teste, use o ReduceDriver que o MRUnit fornece conforme abaixo:
public class MyReducerTest {    ReduceDriver reduceDriver; byte[] CF ="CF".getBytes(); byte[] QUALIFICADOR ="CQ-1".getBytes(); @Before    public void setUp() {      MeuRedutor redutor =new MeuRedutor(); reduzirDriver =ReduceDriver.newReduceDriver(redutor); }     @Test   public void testHBaseInsert() lança IOException {      String strKey ="RowKey-1", strValue ="DATA", strValue1 ="DATA1", strValue2 ="DATA2"; Lista lista =new ArrayList(); list.add(new Text(strValue)); list.add(new Text(strValue1)); list.add(new Text(strValue2)); //já que no nosso caso tudo o que o redutor está fazendo é anexar os registros que o mapeador         //envia, devemos obter o seguinte de volta      String expectoutput =strValue + strValue1 + strValue2; //Configure a entrada, imite qual mapeador teria passado      //para o redutor e execute o teste      reduceDriver.withInput(new Text(strKey), list); //executa o redutor e obtém sua saída      List> result =reduceDriver.run(); //extrai a chave do resultado e verifica      assertEquals(Bytes.toString(result.get(0).getFirst().get()), strKey); //extrai o valor para CF/QUALIFIER e verifica      Coloque a =(Put)result.get(0).getSecond(); String c =Bytes.toString(a.get(CF, QUALIFIER).get(0).getValue()); assertEquals(expectedOutput,c); }}



Basicamente, após um monte de processamento no MyReducer, você verificou que:


  • O resultado é o que você espera.
  • O Put que é inserido no HBase tem "RowKey-1" como a chave de linha.
  • "DATADATA1DATA2" é o valor para a família de colunas CF e o qualificador de coluna CQ.



Você também pode testar mapeadores que obtêm dados do HBase de maneira semelhante usando o MapperDriver ou testar trabalhos de MR que lêem do HBase, processam dados e gravam no HDFS.

Usando um mini-cluster HBase


Agora veremos como fazer o teste de integração. O HBase é fornecido com o HBaseTestingUtility, que simplifica a gravação de testes de integração com um mini-cluster HBase. Para obter as bibliotecas corretas, as seguintes dependências são necessárias em seu pom:
   org.apache.hadoop   hadoop-common   2.0.0-cdh4.2.0   test-jar   test org.apache.hbase   hbase   0.94.2-cdh4.2.0   test-jar   test         org.apache.hadoop   hadoop-hdfs   2.0.0-cdh4.2.0   test-jar   test   org.apache.hadoop   hadoop-hdfs   2.0.0-cdh4.2.0   teste



Agora, vamos ver como executar um teste de integração para a inserção MyDAO descrita na introdução:
classe pública MyHBaseIntegrationTest {utilitário HBaseTestingUtility estático privado;byte[] CF ="CF".getBytes();byte[] QUALIFIER ="CQ-1".getBytes();@Beforepublic void setup() lança Exception { utility =new HBaseTestingUtility(); utility.startMiniCluster();}@Test public void testInsert() lança 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(tabela, obj); Get get1 =new Get(Bytes.toBytes(obj.getRowKey())); get1.addColumn(CF, CQ1); Resultado resultado1 =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); Resultado resultado2 =table.get(get2); assertEquals(Bytes.toString(result2.getRow()), obj.getRowKey()); assertEquals(Bytes.toString(result2.value()), obj.getData2()); }}



Aqui você criou um mini-cluster HBase e o iniciou. Você então criou uma tabela chamada “MyTest” com uma família de colunas, “CF”. Você inseriu um registro usando o DAO que precisava testar, fez um Get da mesma tabela e verificou se o DAO inseriu os registros corretamente.

O mesmo pode ser feito para casos de uso muito mais complicados, juntamente com os trabalhos de RM, como os mostrados acima. Você também pode acessar os mini-clusters HDFS e ZooKeeper criados durante a criação do HBase, executar um trabalho de MR, enviá-lo para o HBase e verificar os registros inseridos.

Apenas uma nota rápida de cautela:iniciar um mini-cluster leva de 20 a 30 segundos e não pode ser feito no Windows sem o Cygwin. No entanto, como eles devem ser executados apenas periodicamente, o tempo de execução mais longo deve ser aceitável.

Você pode encontrar o código de amostra para os exemplos acima em https://github.com/sitaula/HBaseTest. Feliz teste!