InfluxDB is a time series database. Thanks to its high performance datastore it is used as a backing store for any timestamped data, including DevOps monitoring, application metrics, IoT sensor data, and real-time analytics. In this tutorial we will learn how to use it in Java running on the top of WildFly.
As we said, InfluxDB is a database that has been optimized for time series data. Internally its data engine is organized by “time series”, which contain a measured value, like “memory_load” or “temperature”. Time series have zero to many points, one for each discrete sample of the metric. Points consist of time (a timestamp), a measurement (“cpu_load”, for example), at least one key-value field.
In short, you can think of a measurement as an SQL table, where the primary index is always time where the measure is taken. Tags and fields are also columns in the table. The difference with standard Databases is that, with InfluxDB, you can have millions of measurements, you don’t have to define schemas up-front, and null values aren’t stored.
Starting InfluxDB
The download page of InfluxDB contains the possible choices for downloading the product: https://portal.influxdata.com/downloads
To have an instant start, if you have Docker installed, simply launch its image with:
docker run --rm -p 8083:8083 -p 8086:8086 --expose 8090 --expose 8099 --name influxdb tutum/influxdb
Coding a basic application
Now that the database is started, we will code a minimal application which uses it. The Java Client library for InfluxDB is available at: https://github.com/influxdata/influxdb-java/
The simplest way to get started is including the influxdb library in your pom.xml, leaving the default scope so that all required dependencies will be packaged in your application:
<dependency> <groupId>org.influxdb</groupId> <artifactId>influxdb-java</artifactId> <version>2.5</version> </dependency>
The main interface towards InfluxDB is org.influxdb.InfluxDB which allows connecting through a Factory. A CDI friendly approach which @Produces this class is:
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Model; import javax.enterprise.inject.Produces; import javax.inject.Inject; import javax.inject.Named; import org.influxdb.InfluxDB; import org.influxdb.InfluxDBFactory; @ApplicationScoped public class Producer { private InfluxDB influxDB; @Produces @Named public InfluxDB getInfluxDB() { InfluxDB db = InfluxDBFactory.connect("http://172.17.0.2:8086", "root", "root"); String dbName = "java"; // Create a database db.createDatabase(dbName); return db; } }
To keep everything simple, we have hardcoded the database IP Address (which is in our case 172.17.0.2) and the database to create. Now that we have a producer, here’s a simple Servlet which uses InfluxDB to insert one point into our Database:
package demo; import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.influxdb.InfluxDB; import org.influxdb.InfluxDBFactory; import org.influxdb.dto.BatchPoints; import org.influxdb.dto.Point; import org.influxdb.dto.Query; import org.influxdb.dto.QueryResult; @WebServlet("/Test") public class Test extends HttpServlet { @Inject InfluxDB influxDB;; private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); // Create a 'batch' of example 'points' BatchPoints batchPoints = BatchPoints.database("java").tag("async", "true").retentionPolicy("autogen") .consistency(InfluxDB.ConsistencyLevel.ALL).tag("BatchTag", "BatchTagValue") .build(); long free = Runtime.getRuntime().freeMemory(); Point point1 = Point.measurement("memory").time(System.currentTimeMillis(), TimeUnit.MILLISECONDS) .addField("free", free).tag("MemoryTag", "MemoryTagValue") .build(); batchPoints.point(point1); // Write them to InfluxDB influxDB.write(batchPoints); Query query = new Query("SELECT * FROM memory", "java"); QueryResult queryResult = influxDB.query(query); // iterate the results and print details for (QueryResult.Result result : queryResult.getResults()) { // print details of the entire result System.out.println(result.toString()); // iterate the series within the result for (QueryResult.Series series : result.getSeries()) { out.println("series.getName() = " + series.getName()); out.println("series.getColumns() = " + series.getColumns()); out.println("series.getValues() = " + series.getValues()); out.println("series.getTags() = " + series.getTags()); } } out.flush(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
The expected output, is the series which has been just created, which contains the current Free memory in the application server:
series.getName() = memory series.getColumns() = [time, BatchTag, MemoryTag, async, free] series.getValues() = [[2017-02-22T14:59:31.14Z, BatchTagValue, MemoryTagValue, true, 7.9285432E7]] series.getTags() = null
As a proof of concept, jump into the InfluxDB Web application and check the following query:
select * from memory
Here’s our measure just inserted:
As side note, in this simple example we haven’t included it, but you are able to remove a database as well with the following method:
// Delete the database influxDB.deleteDatabase("java");
Installing InfluxDB as a module
If you want to reuse InfluxDB across several applications, it might be worthy to install it as a module. You will need, besides the influxdb-java JAR file, all these libraries in your main module folder:
converter-moshi-2.1.0.jar guava-20.0.jar influxdb-java-2.5.jar logging-interceptor-3.5.0.jar moshi-1.2.0.jar okhttp-3.5.0.jar okio-1.11.0.jar retrofit-2.1.0.jar
And here is the needed module.xml:
<module xmlns="urn:jboss:module:1.1" name="com.influxdb"> <resources> <resource-root path="influxdb-java-2.5.jar" /> <resource-root path="converter-moshi-2.1.0.jar" /> <resource-root path="guava-20.0.jar" /> <resource-root path="logging-interceptor-3.5.0.jar" /> <resource-root path="moshi-1.2.0.jar" /> <resource-root path="okhttp-3.5.0.jar" /> <resource-root path="okio-1.11.0.jar" /> <resource-root path="retrofit-2.1.0.jar" /> </resources> <dependencies> <module name="javax.api" /> </dependencies> </module>
As libraries are now available in the server, you can set as “provided” your influxdb-java dependency:
Later we will see how to install the InfluxDB libraries as a module:
<dependency> <groupId>org.influxdb</groupId> <artifactId>influxdb-java</artifactId> <version>2.5</version> <scope>provided</scope> </dependency>
That’s all! In the next tutorial Displaying application server metrics with Grafana we will learn how to use Grafana to display Dashboards from InfluxDB Datasource.