Google Cloud Bigtable
SGBD´s, ou sistemas gerenciadores de bancos de dados, são utilizados há muito tempo. Soluções famosas como Oracle, Postgres, MySQL estão entre as mais populares. Uma característica que as três soluções mencionadas compartilham é o suporte primário ao modelo relacional para armazenamento de dados. Hoje em dia, existem diversas opções de bancos de dados que podem ser muito mais performáticos do que bancos de dados relacionais para necessidades especificas, essas soluções são englobadas em uma categoria denominada NoSQL (Not Only SQL). Dentro do universo NoSQL temos bancos orientados a chave-valor, colunares, documentos, séries temporais, entre outras opções.
Onde o Bigtable se enquadra?
O Bigtable é um banco NoSQL voltado para o armazenamento de dados no esquema chave-valor. A solução é totalmente gerenciada pela Google e suporta bilhões de registros, milhares de colunas e Peta bytes de dados. Suas características o tornam uma solução interessante para aplicações que armazenam grandes volumes de dados, e demandam alto volume de consultas e escritas com baixa latência.
Um case de uso interessante onde podemos considerar o Bigtable é o armazenamento de dados financeiros baseados em séries temporais. Necessidade essa muito comum em soluções que atendem o mercado acionário.
Demonstração prática
Não vou entrar nos detalhes de como criar uma conta na GCP, mas basta acessar a página https://cloud.google.com/ e seguir o passo a passo. Ao criar uma conta na GCP, são disponibilizados $300 em créditos para serem utilizados em até 90 dias. Muito mais do que o necessário para essa demonstração.
Uma vez logado no console do GCP, vamos primeiramente criar um projeto dedicado para a demonstração, depois é só apagar o projeto inteiro a fim de evitar cobranças.

Após criar o projeto, vamos acessar o painel de controle do Bigtable. No menu lateral, do lado esquerdo, basta clicar em Bigtable na seção Bancos de Dados.

Na sequência, crie uma instância do Bigtable:
Detalhe para o preço em destaque. Então, cuidado para não deixar a instância no ar sem necessidade =):

Agora, basta preencher os campos e clicar em “create”.

A instância criada foi definida com apenas um node. Essa propriedade afeta a performance da instância e o custo. Ela pode ser atualizada a qualquer momento. Para o nosso case, 1 node é mais do que o suficiente.
Caso amanhã precisemos aprimorar a performance da nossa instância, basta voltar aqui e incluir mais nodes.
Ao clicar no nome da instância, teremos acesso ao painel geral que oferece uma série de estatísticas sobre ela:

No menu lateral, acesse a opção “Table”. Conforme a imagem, ainda não temos nenhuma tabela:

Nosso case de estudo
Vamos ilustrar um cenário onde se faz necessário a criação de uma aplicação que irá expor uma API, para consulta a dados de uma série temporal com valores históricos de um conjunto de ativos financeiros da bolsa de valores brasileira.
Trabalhando no design da tabela
A estrutura de dados necessária é a seguinte:
Família A | Família B | Família C | ||||||
Rowkey | Ativo | Data | Alta | Baixa | Abertura | Fechamento | Volume | Fechamento Ajustado |
Pontos importantes:
1- Rowkey: É o identificador único de um registro. A definição da nossa chave deve ser bem planejada, pois influenciará muito na performance de nossa instância do Bigtable.
Algo a ser evitado é a criação de uma rowkey baseada simplesmente em números sequenciais ou datas. Isto porque o Bigtable irá ordenar os registros através dessa coluna, e dependendo do schema/volume de dados e das características das consultas que serão realizadas, nossa aplicação pode ser prejudicada.
Para o nosso cenário, uma proposta interessante de chave é compor a mesma pelo nome do ativo e data do registro.
nomeAtivo#yyyymmdd |
Exemplo:
BBDC4#20200121 |
Dessa forma, o mecanismo de ordenação do Bigtable vai organizar os registros por ativo e data, o que, no nosso caso, vai aprimorar a performance das consultas.
2- Famílias: Conforme mencionado. o Bigtable suporta milhares de colunas, e, a fim de colaborar com a organização das colunas, é possível agrupá-las em famílias. No caso, agrupamos algumas colunas apenas para fins de demonstração.
Para o nosso case, vamos trabalhar com uma base de dados disponibilizada aqui. Trata-se de um arquivo csv com o histórico de preços de alguns ativos da bolsa de valores brasileira. O histórico é do ano de 2020.
Abaixo, temos uma amostragem dos dados:
Ativo | Data | Alta | Baixa | Abertura | Fechamento | Volume | Fechamento Ajustado |
BBDC4 | 02/01/2020 | 34,09999847 | 32,90908813 | 33,20909119 | 34,09999847 | 20687260 | 33,07200241 |
BBDC4 | 03/01/2020 | 34,54545212 | 33,52727127 | 33,54545212 | 34,09999847 | 33057090 | 33,08722305 |
BBDC4 | 06/01/2020 | 33,89090729 | 33,12727356 | 33,81818008 | 33,49090958 | 27830990 | 32,49622345 |
BBDC4 | 07/01/2020 | 33,59999847 | 32,72727203 | 33,40908813 | 32,90908813 | 16343030 | 31,9316864 |
BBDC4 | 08/01/2020 | 33,20000076 | 32,23636246 | 33,06363678 | 32,40000153 | 23393480 | 31,43770599 |
BBDC4 | 09/01/2020 | 32,62727356 | 31,56363678 | 32,52727127 | 31,88181877 | 25437390 | 30,93491936 |
Usando o CBT para criar a tabela, inserir e consultar dados
Agora que já conhecemos o nosso conjunto de dados, vamos começar a interagir com o BigTable. Ele dispõe de uma ferramenta padrão para interação, trata-se do CBT ou “Cloud Bigtable Command Line Tool”. Vamos fazer uso do CBT através do Cloud Shell. Por padrão, o Cloud Shell já vem com o CBT instalado, caso estivéssemos acessando a partir de nossa máquina seria necessário instalá-lo.
O usuário que estou usando possui privilégios administrativos, caso contrário eu precisaria atribuir privilégios para interagir com o Bigtable.
Uma vez no Cloud Shell, vamos precisar criar um arquivo denominado “.cbtrc”. Defina nesses arquivos duas variáveis:
project = [id-do-seu-projeto] (ID e não o nome)
instance = [nome-de-sua-instância-bigtable]
Esse arquivo é necessário para que não precisemos informar essas constantes em todos os comandos. Feito isso, podemos testar o CBT através do comando abaixo:
cbt version
Será aberta uma janela solicitando autorização para acessar APIs internas. Basta dar OK. A saída do comando será algo semelhante ao que segue abaixo:

Agora, vamos criar a nossa tabela com o comando abaixo:
cbt createtable historicoAtivos
Podemos validar que nossa tabela foi criada através do seguinte comando:

Crie as Column Families da nossa tabela:
cbt createfamily historicoAtivos familiaA
cbt createfamily historicoAtivos familiaB
cbt createfamily historicoAtivos familiaC
Podemos validar as Column Families criadas através do comando abaixo:
cbt ls historicoAtivos

Agora, insira um registro na tabela:
cbt set historicoAtivos BBDC4#04/01/2020 familiaA:ativo=BBDC4 familiaA:data=02/01/2020 familiaB:alta=34.09999847 familiaB:baixa=32.90908813 familiaB:abertura=33.20909119 familiaB:fechamento=34.09999847 familiaC:volume=20687260 familiaC:fechamentoAjustado=33.07200241
Podemos consultar o registro inserido com o seguinte comando:
cbt read historicoAtivos

Podemos apagar os registros da tabela com este comando:
cbt deleteallrows historicoAtivos
Após isto, insira 8 registros através dos comandos do arquivo localizado aqui. Abaixo seguem as rowkeys dos registros em questão:

Após inseri-los, podemos consultar a quantidade de registros disponíveis através destee comando:
cbt count historicoAtivos

Agora, selecione apenas os registros da MGLU3:
cbt read historicoAtivos prefix=MGLU3
E aqui vamos selecionar os registros da MGLU3 de 01/01/2019 até 02/01/2020:
cbt read historicoAtivos start=MGLU3#20190101 end=MGLU3#20200102
Apenas um registro atende ao filtro (o valor informado para o atributo END não é considerado):

Interagindo com o BigTable através de bibliotecas
O CBT é uma ferramenta interessante para fins de testes e consultas rápidas. Porém, pensando em soluções de software, precisaremos fazer uso de bibliotecas para fins de integração. O BigTable oferece as seguintes opções:
C++ | C# | Java | Go | HBase (Java) | Node.js | PHP | Python | Ruby |
Vamos realizar alguns testes através da opção nativa para Java:
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-bigtable</artifactId>
<version>1.5.0</version>
</dependency>
Consulte um registro pela rowkey:
private void getRecordsByKey( String key) {
try {
Row row = this.dataClient.readRow(Constantes.BT_TABLE_ID, key);
printRecord(row);
} catch (Exception e) {
System.out.println(“Error getRecordsByKey”);
e.printStackTrace();
}
}
E consulte registros por faixa de valores:
private void getRecordsByKeyRange(String start, String end) {
try {
Query query = Query.create(Constantes.BT_TABLE_ID).range(start, end);
ServerStream<Row> rows = this.dataClient.readRows(query);
rows.forEach(r->printRecord(r));
} catch (Exception e) {
System.out.println(“Error getRecordsByKeyRange”);
e.printStackTrace();
}
}
O projeto com a implementação dos métodos acima e de alguns métodos extras pode ser encontrado aqui.
Resumo
Nesse artigo conhecemos um pouco do Bigtable, seus conceitos e a importância de uma modelagem correta. Verificamos alguns exercícios práticos, para interação com o banco de dados através do CBT e também através da biblioteca Java.
Referências
[Google Bigtable]https://cloud.google.com/bigtable
[Treinamentos Google Bigtable]https://cloud.google.com/bigtable/docs#training-and-tutorials
[Hello world com java]https://cloud.google.com/bigtable/docs/samples-java-hello-world
[Github do projeto apresentado]