Usando o InfluxDB com Java

Usando o InfluxDB com Java

1. Visão geral

InfluxDB is a high-performance store for time-series data. Suporta inserção e consulta em tempo real de dados por meio de uma linguagem de consulta semelhante a SQL.

Neste artigo introdutório, demonstraremos como se conectar a um servidor InfluxDb, criar um banco de dados, gravar informações de série temporal e, em seguida, consultar o banco de dados.

2. Configuração

Para conectar ao banco de dados, precisaremos adicionar uma entrada ao nosso arquivopom.xml:


    org.influxdb
    influxdb-java
    2.8

A versão mais recente desta dependência pode ser encontrada emMaven Central.

Também precisaremos de uma instância do InfluxDB. As instruções paradownloading and installing a database podem ser encontradas no siteInfluxData.

3. Conectando a um servidor

3.1. Criando uma conexão

A criação de uma conexão de banco de dados requer a passagem de um URLStringe credenciais de usuário para um connection factory:

InfluxDB influxDB = InfluxDBFactory.connect(databaseURL, userName, password);

3.2. Verificando a conexão

Communications with the database are performed over a RESTful API, então eles não são persistentes.

A API oferece um serviço "ping" dedicado para confirmar que a conexão está funcionando. Se a conexão estiver boa, a resposta conterá uma versão do banco de dados. Caso contrário, contém“unknown”.

Portanto, depois de criar uma conexão, podemos verificá-la fazendo:

Pong response = this.influxDB.ping();
if (response.getVersion().equalsIgnoreCase("unknown")) {
    log.error("Error pinging server.");
    return;
}

3.3. Criando um banco de dados

Criar um banco de dados do InfluxDB é semelhante a criar um banco de dados na maioria das plataformas. But we need to create at least one retention policy before using it.

A retention policy tells the database how long a piece of data should be stored. As séries temporais, como estatísticas de CPU ou memória, tendem a se acumular em grandes conjuntos de dados.

Uma estratégia típica para controlar o tamanho dos bancos de dados de série temporal édownsampling. Os dados "brutos" são armazenados a uma taxa alta, resumidos e removidos após um curto período de tempo.

Retention policies simplify this by associating a piece of data with an expiration time. InfluxData tem umin-depth explanation em seu site.

Depois de criar o banco de dados, adicionaremos uma única política chamadadefaultPolicy.. Ela simplesmente reterá os dados por 30 dias:

influxDB.createDatabase("example");
influxDB.createRetentionPolicy(
  "defaultPolicy", "example", "30d", 1, true);

Para criar uma política de retenção, vamos precisar dename,database,interval,areplication factor (que deve ser 1 para um banco de dados de instância única) eboolean indicando que é uma política padrão.

3.4. Definir um nível de registro

Internamente, a API do InfluxDB usaRetrofite expõe uma interface para o recurso de registro do Retrofit, por meio de umlogging interceptor.

Portanto, podemos definir o nível de log usando:

influxDB.setLogLevel(InfluxDB.LogLevel.BASIC);

E agora podemos ver as mensagens quando abrimos uma conexão e fazemos ping:

Dec 20, 2017 5:38:10 PM okhttp3.internal.platform.Platform log
INFO: --> GET http://127.0.0.1:8086/ping

Os níveis disponíveis sãoBASIC,FULL,HEADERS eNONE.

4. Adicionar e recuperar dados

4.1. Pontos

Portanto, agora estamos prontos para começar a inserir e recuperar dados.

A unidade básica de informação no InfluxDB é umPoint, que é essencialmente um carimbo de data / hora e um mapa de valor-chave.

Vamos dar uma olhada em um ponto que contém os dados de utilização da memória:

Point point = Point.measurement("memory")
  .time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
  .addField("name", "server1")
  .addField("free", 4743656L)
  .addField("used", 1015096L)
  .addField("buffer", 1010467L)
  .build();

Criamos uma entrada que contém trêsLongs como estatísticas de memória, um nome de host e um carimbo de data / hora.

Vamos ver como adicionar isso ao banco de dados.

4.2. Escrevendo lotes

Time series data tends to consist of many small points, and writing those records one at a time would be very inefficient. O método preferido é coletar registros em lotes.

A API do InfluxDB fornece um objetoBatchPoint:

BatchPoints batchPoints = BatchPoints
  .database(dbName)
  .retentionPolicy("defaultPolicy")
  .build();

Point point1 = Point.measurement("memory")
  .time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
  .addField("name", "server1")
  .addField("free", 4743656L)
  .addField("used", 1015096L)
  .addField("buffer", 1010467L)
  .build();

Point point2 = Point.measurement("memory")
  .time(System.currentTimeMillis() - 100, TimeUnit.MILLISECONDS)
  .addField("name", "server1")
  .addField("free", 4743696L)
  .addField("used", 1016096L)
  .addField("buffer", 1008467L)
  .build();

batchPoints.point(point1);
batchPoints.point(point2);
influxDB.write(batchPoints);

Criamos umBatchPointe adicionamosPoints a ele. Definimos o carimbo de data e hora da segunda entrada para 100 milissegundos no passado, pois os carimbos de hora são um índice primário. Se enviarmos dois pontos com o mesmo timestamp, apenas um será mantido.

Observe que devemos associarBatchPoints a um banco de dados e uma política de retenção.

4.3. Escrevendo um de cada vez

Lote pode ser impraticável para alguns casos de uso.

Vamos ativar o modo em lote com uma única chamada para uma conexão InfluxDB:

influxDB.enableBatch(100, 200, TimeUnit.MILLISECONDS);

Ativamos lotes de 100 para inserção no servidor ou envio do que ele possui a cada 200 milissegundos.

Com o modo em lote ativado, ainda podemos escrever um de cada vez. No entanto, é necessária alguma configuração adicional:

influxDB.setRetentionPolicy("defaultPolicy");
influxDB.setDatabase(dbName);

Além disso, agora podemos escrever pontos individuais e eles estão sendo coletados em lotes por um thread em segundo plano:

influxDB.write(point);

Before we enqueue individual points, we need to set a database (semelhante ao comandouse em SQL)and set a default retention policy. Portanto, se quisermos aproveitar a redução da resolução com políticas de retenção múltiplas, a criação de lotes é o caminho a percorrer.

O modo em lote utiliza um pool de threads separado. Portanto, é uma boa ideia desativá-lo quando não for mais necessário:

influxDB.disableBatch();

Fechar a conexão também encerrará o pool de threads:

influxDB.close();

4.4. Resultados da consulta de mapeamento

As consultas retornam umQueryResult, que podemos mapear para POJOs.

Antes de examinarmos a sintaxe da consulta, vamos criar uma classe para manter nossas estatísticas de memória:

@Measurement(name = "memory")
public class MemoryPoint {

    @Column(name = "time")
    private Instant time;

    @Column(name = "name")
    private String name;

    @Column(name = "free")
    private Long free;

    @Column(name = "used")
    private Long used;

    @Column(name = "buffer")
    private Long buffer;
}

A classe é anotada com@Measurement(name = “memory”), correspondendo aPoint.measurement(“memory”) que usamos para criar nossoPoints.

Para cada campo em nossoQueryResult, adicionamos a anotação@Column(name = “XXX”) com o nome do campo correspondente.

QueryResults são mapeados para POJOs com umInfluxDBResultMapper.

4.5. Consultando InfluxDB

Então, vamos usar nosso POJO com os pontos que adicionamos ao banco de dados em nosso lote de dois pontos:

QueryResult queryResult = connection
  .performQuery("Select * from memory", "example");

InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
List memoryPointList = resultMapper
  .toPOJO(queryResult, MemoryPoint.class);

assertEquals(2, memoryPointList.size());
assertTrue(4743696L == memoryPointList.get(0).getFree());

A consulta ilustra como nossa medida chamadamemory é armazenada como uma tabela dePoints da qual podemosselect.

InfluxDBResultMapper aceita uma referência aMemoryPoint.class comQueryResulte retorna uma lista de pontos.

Depois de mapear os resultados, verificamos que recebemos dois verificando o comprimento dosList que recebemos da consulta. Em seguida, olhamos para a primeira entrada na lista e vemos o tamanho da memória livre do segundo ponto que inserimos. The default ordering of query results from InfluxDB is ascending by timestamp.

Vamos mudar isso:

queryResult = connection.performQuery(
  "Select * from memory order by time desc", "example");
memoryPointList = resultMapper
  .toPOJO(queryResult, MemoryPoint.class);

assertEquals(2, memoryPointList.size());
assertTrue(4743656L == memoryPointList.get(0).getFree());

Adicionarorder by time desc inverte a ordem dos nossos resultados.

As consultas do InfluxDB são muito semelhantes ao SQL. Há um guia de referência extensoon their site.

5. Conclusão

Conectamos a um servidor InfluxDB, criamos um banco de dados com uma política de retenção e, em seguida, inserimos e recuperamos os dados do servidor.

O código-fonte completo dos exemplos éover on GitHub.