Pontos Principais
-
O gerenciamento de dados temporais é fundamental para qualquer iniciativa focada na análise de dados empresariais. Exemplos de dados temporais são os preços das ações, telemetria de sensores de maquinas industriais, ou as métricas de desempenho de servidores.
-
Os bancos de dados de séries temporais criados para fins específicos, como o RedisTimeSeries, atendem às necessidades de manipulação destes tipos de dados e também removem as limitações impostas pelos bancos de dados relacionais;
-
Outros bancos de dados criados especificamente para dados de séries temporais incluem o InfluxDB e o Prometheus;
-
Ao integrar o Grafana e RedisTimeSeries, podemos em tempo real, visualizar padrões e detectar anomalias, visualizar tendências e comparar dados atuais com dados históricos, agregar dados, e outras coisas mais.
Os dados de séries temporais são amplamente definidos como uma série de dados armazenados em ordem cronológica, em outras palavras, cada valor tem um tempo associado a ele.
Características dos dados de séries temporais
Os dados de séries temporais geralmente são ineficientes quando gerenciados com outros bancos de dados e isso se deve às seguintes características:
- Ingestão de dados em alta velocidade: Seja um caso de uso da IoT ou dados de análise de mercado, temos um fluxo constante de dados que chega em alta velocidade e frequentemente em grandes pacotes de uma vez. Para a maioria das soluções, os dados chegam 24/7, 365 dias por ano;
- Dados imutáveis: Uma vez inserido no banco de dados, um datapoint não sofre nenhuma alteração até que seja removido de forma manual ou automática (através de regras de expiração, por exemplo);
- Metadados não estruturados: Os dados de séries temporais geralmente são produzidos continuamente por um longo período por diversas fontes. Em um caso de uso da IoT, todo sensor é uma fonte de dados de séries temporais, nessas situações, cada ponto de dados da série armazena as informações da fonte e outras medidas do sensor como metadados. Os metadados de todas as fontes podem não estar em conformidade com a mesma estrutura ou ainda não terem ordem na cadastro semelhante;
- Valor diminuído ao longo do tempo: Conforme os dados vão ficando velhos, normalmente perdem relevância, o que nos leva a definir regras de agregação e ou expiração de dados. Daqui a um ano, a maioria dos usuários não irá necessitar dos dados armazenados no intervalo de milissegundos. Somente dados agregados e generalizados por um minuto, hora ou dia fazem sentido nesses casos de dados históricos;
- Consultas agregadas por intervalo de tempo: Os gráficos baseados em dados de séries temporais permitem visualizar com maior ou menor granularidade a informação para um determinado intervalo temporal. Normalmente, a consultas que abranjam um maior intervalo temporal, está associada uma redução da granularidade, pois não temos interesse em saber os valores de cada minuto num intervalo de um ano, e normalmente queremos um valor agregado abrangente com o valor médio/mínimo/máximo por dia ou semana.
Problemas ao utilizar os bancos de dados relacionais para casos de uso de dados temporais
Muitas soluções ainda armazenam dados de séries temporais em um banco de dados relacional. Essa abordagem tem diversas desvantagens, porque estas estruturas relacionais:
- São projetados e otimizados para casos de uso transacionais;
- Possuem sobrecarga de bloqueio e sincronização, que não são necessárias para os dados imutáveis de séries temporais. Isso resulta em um pior desempenho para a inclusão de dados e consultas. As empresas acabam investindo em recursos computacionais adicionais para conseguirem expandir;
- Aplicam uma estrutura rígida para os metadados e não conseguem acomodar os dados não estruturados;
- As regras de agregação e expiração para dados antigos requerem complexidade adicional por parte do administrador do banco de dados;
- São usados para muitos outros casos de uso. O uso excessivo de consultas de séries temporais pode afetar outras cargas de trabalho.
Repensando o banco de dados para dados temporais
Alguns bancos de dados criados especificamente para dados de séries temporais incluem o Influx DB e o Prometheus. Dentro do ecossistema Redis, o módulo RedisTimeSeries foi desenvolvido especificamente para coletar, gerenciar e fornecer dados de séries temporais em escala. Algumas de suas características são:
- Ingestão rápida de dados: Como um banco de dados na memória, o RedisTimeSeries pode ingerir mais de 500.000 registros por segundo em um servidor padrão. Alguns benchmarks mostram que podemos cadastrar mais de 11,5 milhões de registros por segundo com um cluster de 16 shards;
- Eficiência de recursos: Com RedisTimeSeries, podemos adicionar regras para compactar dados reduzindo a granularidade e consequentemente o espaço em memória. Por exemplo, se tivermos coletado mais de um bilhão de pontos de dados em um único dia, poderemos agregar os dados a cada minuto, reduzindo assim o tamanho do conjunto de dados para 24 * 60 = 1.440 pontos de dados. Também podemos definir políticas de retenção e expiração de dados quando não precisarmos mais deles.
Imagem 1: Downsampling e agregação usando um banco de dados de séries temporais
- Consultas fáceis e rápidas: O RedisTimeSeries permite agregar dados por média, mínimo, máximo, e outros tipos de agregações mais complexas. Podemos executar mais de 100.000 consultas de agregação por segundo com latência abaixo dos milissegundos.
Devemos considerar usar este módulo se tivermos requisitos de tempo real tanto no cadastro quanto nas consultas dos dados. As grandes vantagens do RedisTimeseries em relação aos seus concorrentes são a baixa latência e alta escalabilidade, tudo isto porque é um banco de dados em memória. Outras opções baseadas em disco (InfluxDB, Prometheus) poderão ser mais adequadas se não tivermos o requisito de tempo real e a aplicação não for sensível a altas latências. Todas as soluções possuem pontos positivos que sempre será necessário fazer uma decisão ajustada aos requisitos do nosso sistema/aplicação.
Um guia rápido para os iniciantes no RedisTimeSeries
A forma mais rápida de iniciar o RedisTimeSeries é adicioná-lo como fonte de dados ao nosso painel Grafana. Na próxima seção deste artigo, mostraremos como carregar os dados de séries temporais no RedisTimeSeries e visualizar os dados em tempo real.
Optamos por comparar o desempenho dos preços das ações da Apple Inc. (AAPL) e Intel Inc. (INTC) durante 19 anos, usando um gráfico no painel Grafana:
Imagem 2: Comparação do desempenho das ações da Apple e Intel usando RedisTimesSeries e Grafana
A configuração do RedisTimeSeries
Vamos começar baixando o código-fonte do RedisTimeSeries do GitHub e fazendo um build local, importando o arquivo ".so" para o Redis usando o comando:
MODULE LOAD [caminho para]/redistimeseries.so
Também podemos carregar o módulo inserindo o seguinte comando no redis.conf:
loadmodule [caminho para]/redistimeseries.so
Se preferirmos usar Docker, segue o comando necessário:
docker run -p 6379:6379 -it --rm redislabs/redistimeseries
Depois de iniciarmos o servidor Redis, podemos observar se elecarregou corretamente o módulo executando o command "module list".
127.0.0.1:6379> module list
1) 1) "name"
2) "timeseries"
3) "ver"
4) (integer) 200
Dados de amostra: mais de 19 anos de dados do mercado de ações
Para exemplificar potenciais casos de uso, baixamos os preços diários das ações da AAPL e da INTC no Wall Street Journal. O arquivo inclui preços do ano 2000 até a data de hoje no formato .csv (valores separados por vírgula). Aqui está uma amostra dos dados da AAPL:
2006-01-03,10.34,10.68,10.32,10.68,201853036,AAPL
2006-01-04,10.73,10.85,10.64,10.71,155225609,AAPL
2006-01-05,10.69,10.7,10.54,10.63,112396081,AAPL
2006-01-06,10.75,10.96,10.65,10.9,176139334,AAPL
2006-01-09,10.96,11.03,10.82,10.86,168861224,AAPL
2006-01-10,10.89,11.7,10.83,11.55,570088246,AAPL
2006-01-11,11.98,12.11,11.8,11.99,373548882,AAPL
2006-01-12,12.14,12.34,11.95,12.04,320201966,AAPL
2006-01-13,12.14,12.29,12.09,12.23,194153393,AAPL
2006-01-17,12.24,12.34,11.98,12.1,209215265,AAPL
Em seguida, com um simples script em Python podemos importar os dados para o RedisTimeSeries:
import sys
import csv
import time
import redis
if(len(sys.argv) > 1):
ticker = str(sys.argv[1])
else:
ticker = test
file = ticker + .csv
r = redis.Redis(host=localhost, port=6380, db=0)
with open(file) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=",")
r.execute_command("ts.create stock:"+ticker);
count = 0
for row in csv_reader:
time_tuple = time.strptime(row[0], %Y-%m-%d)
time_epoch = time.mktime(time_tuple)*1000
r.execute_command("ts.add stock:"+ticker+" "+str(int(time_epoch))+" "+row[1])
count = count + 1
print(fImported {count} lines)
Como podemos observar, usamos o comando TS.CREATE
do RedisTimeSeries para estabelecer uma nova estrutura de dados de séries temporais e o comando TS.ADD
para adicionar os dados. Para o símbolo AAPL, este programa criou uma estrutura de dados chamada stock:aapl
. Um exemplo de comando de inclusão de dados é semelhante a:
TS.ADD stock:aapl 1513324800000 173.04
Estamos prontos para executar uma query no dataset criado. Para fazer isso, usamos o comando TS.RANGE
. Observe que os timestamps usados nesta consulta estão em milissegundos.
127.0.0.1:6379> TS.RANGE stock:aapl 1513324800000 1514324800000 aggregation avg 1
1) 1) (integer) 1513324800000
2) "173.63"
2) 1) (integer) 1513584000000
2) "174.88"
3) 1) (integer) 1513670400000
2) "174.99000000000001"
4) 1) (integer) 1513756800000
2) "174.87"
5) 1) (integer) 1513843200000
2) "174.16999999999999"
6) 1) (integer) 1513929600000
2) "174.68000000000001"
7) 1) (integer) 1514275200000
2) "170.80000000000001”
No próximo passo, vamos explicar como usar o Grafana para visualizar e comparar os preços das ações.
Visualizando os dados no Grafana
Nesta seção, vamos mostrar como instalar o Grafana e utilizar o conector de dados SimpleJSON para lermos os dados do RedisTimeSeries. Para isso, desenvolvemos uma aplicação de fonte de dados SimpleJSON nova. É uma aplicação intermediária feita em Node.js baseada em HTTP que traduz chamadas SimpleJSON em chamadas Redis e dados RedisTimeSeries em dados JSON.
Passo 1: Instalando o Grafana
Primeiro, vamos usar o homebrew para instalar o Grafana no Mac (se estivermos usando Windows ou uma distribuição Linux, siga o manual de instruções do Grafana para instalá-lo e configurá-lo). Execute os seguintes comandos para executar o Grafana:
$ brew install grafana
$ brew services start grafana
==> Successfully started `grafana` (label: homebrew.mxcl.grafana)
Com o Grafana utilizando a porta 3000, podemos efetuar o login usando http://localhost:3000.
Passo 2: Desenvolver e executar a aplicação de fonte de dados SimpleJSON
O Grafana vem com um conector de fonte de dados interno chamado SimpleJSON, que se conecta a qualquer aplicativo com um servidor HTTP compatível com "/", "/search" e "/query". Como o RedisTimeSeries ainda não possui um conector próprio, desenvolvemos uma nova aplicação Node.js que suporta o protocolo HTTP e as consultas necessárias para a aplicação de fonte de dados SimpleJSON. Podemos fazer o download do código-fonte no GitHub e executá-lo no ambiente local do Node.js.
Cada consulta HTTP na aplicação de fonte de dados do SimpleJSON tem um propósito único e desenvolvi o programa com os seguintes princípios de design para cada um:
1. "/": Esta é requisição padrão que deve responder com uma mensagem arbitrária. É usada para testar a conexão (como um teste de ping).
2. "/search": Retorna a lista de chaves que contêm os dados da série temporal. Nos outros bancos de dados, seria a listagem dos nomes das tabelas em vez das chaves, porém, como o Redis armazena em valores-chave, retornamos a lista das chaves que são do tipo especial para uma série temporal.
Para obter esta lista de chaves, usamos o comando SCAN
por ser mais seguro, em vez do KEYS
. Para cada chave, verificamos se era do tipo TSDB-TYPE
, o nome interno que usamos para chaves de séries temporais. O programa mantém uma matriz de todas as chaves desse tipo e retorna a matriz no formato JSON.
3. "/query": O comando query recebe argumentos de entrada que incluem a lista de chaves, horário de início e término, além do horário do bucket. A aplicação retorna os dados de séries temporais no formato JSON com base nos comandos de entrada.
Há também uma quarta requisição HTTP, chamada "/annotations", mas não iremos utilizá-la nesta demonstração.
Depois que o código ficou pronto, executamos a aplicação do nó ativo. O código ouve as solicitações HTTP na porta 3333, para que pudéssemos testá-la em um navegador usando o http://localhost:3333. A requisição retornou: "I have a quest for you!"
Passo 3: Conectar o Grafana ao RedisTimeSeries
Esse foi o passo mais fácil. Após fazer login no Grafana, adicionamos uma fonte de dados no Configuration > Data Sources, e posteriormente clicando em "Add data source".
Procure a opção SimpleJSON e a selecione-a.
Isso deve abrir uma tela de configuração, onde deverá ser inserido a URL para se conectar a aplicação Node.js.
Agora que temos a fonte de dados configurada, é possível adicionar novos gráficos ao nosso painel. Neste exemplo, adicionamos um painel com duas consultas: Uma consulta de série temporal para cada cotação de ações. Como mostra a figura, o menu dropdown da consulta já preenchia o estoque de chaves da série temporal: stock:aapl e stock:intc. Por trás, o conector SimpleJSON chamará a aplicação com as requisições apropriadas ("/search" e "/query").
Este é o resultado final: Um painel da Grafana consultando o RedisTimeSeries. É simples configurar o RedisTimeSeries e conectá-lo ao Grafana.
Conclusões
O RedisTimeSeries combina todos os benefícios do Redis e um banco de dados de séries temporais podendo ajudar a área de negócios das empresas de várias maneiras diferentes, inclusive economizando recursos, dando suporte a mais usuários finais, levando as aplicações mais rapidamente ao mercado, com fácil integração. Ao integrar o Grafana ao RedisTimeSeries, podemos aumentar ou diminuir o zoom nas consultas em tempo real. Também podemos lidar com várias consultas por segundo, permitindo que o painel mostre mais pontos de dados. Além disso, podemos adicionar mais painéis e atender a mais usuários finais.
Sobre o Autor
Roshan Kumar é um gerente de produtos sênior na Redis Labs, Inc. Ele tem vasta experiência em desenvolvimento de software e gestão de produtos no setor de tecnologia. No passado Kumar trabalhou na Hewlett-Packard, e em algumas startups de sucesso no Vale do Silício, Ele é formado em Ciência da computação e tem um MBA na Santa Clara University, Califórnia, USA.