Time Series Database Comparison
By: Israel Imru
Tags: Internet of Things, Data Science, Time Series Database, Big Data, Time Series

Introduction

A time series is a series of data points of some particular metric (and its tags) over time.

Picking a new (time series) database can oftentimes be difficult. Though the choice can sometimes seem like an agonizing decision, the best method of combating this sort of paralyzing fear is to enter the decision making process with as much information as possible. This blog aims to educate — with rather broad strokes — the differences between some of the heaviest hitters in the Time Series Database (TSDB) space. We will go through each of the following databases one by one and try to parse out general weaknesses and strengths: InfluxDB, TimescaleDB, OpenTSDB, and GridDB.

InfluxDB

InfluxDB was first released in 2013 and is written primarily in Google’s Go. It is maintained by InfluxData and is currently the #1 TSDB in use.

TimescaleDB

Written in C, TimescaleDB is based on the ever-popular and more “traditional” relational database PostgreSQL. This means that developers who are familiar with SQL will likely feel extremely comfortable with this database.

OpenTSDB

OpenTSDB was written in Java and runs entirely on top of Hadoop and HBase. Hadoop is a software suite which uses MapReduce to properly process very big data. HBase is a database modeled after Google’s Bigtable. Because of this, it may sometimes be considered to be a bit difficult to use.

GridDB

Toshiba started development for GridDB in 2011, with its commercial release coming in 2013; it was then open-sourced in 2016. GridDB is written in C++ and has language bindings for a ton of other languages. It has also been integrated with other open source projects such as MapReduce, KairosDB, Grafana, and Spark.

Basic Usage & Query Language

As a first point of comparison, let’s take a look at writing extremely simple writes and queries, just to get a quick peek at how exactly each database looks and feels.

InfluxDB

InfluxDB operates most usually via HTTP. Because you can make simple HTTP GET requests via its API, the easiest way to get up and running is to simply use the command line interface (CLI). From here, you drop down into an InfluxDB shell and query using its own query language: Influx Query Language (InfluxQL). Each data entry can be thought of as a traditional SQL table, with a timestamp always being the primary index. Each measurement will also contain tags for meta data (such as location, sensor name, etc) all of which can be thought of as columns and of which are indexed.

Here’s an example of using InfluxQL to insert some sample data.

> INSERT cpu,host=serverA,region=us_west value=0.64

The measurement name is cpu. Host and region are tags. The value is the value. The timestamp will be the current local timestamp (if none is specified).

To query:

> SELECT “host”, “region”, “value” FROM “cpu”

name: cpu

— — — — -

time host region value

2015–10–21T19:28:07.580664347Z serverA us_west 0.64

TimescaleDB

As mentioned before, TimescaleDB is built on top of PostgreSQL, meaning it gets a full and native SQL interface. Though it uses full SQL, it does offer some key advantages, including some added time-specific functions, that can push it over-the-top as a nice option for your time-related data and time-related applications. First, it’s much faster at certain queries, namely those involving time series data; in some cases climbing to up to over 20x faster. It also boasts much higher ingest rates (again, this is compared to “stock” PostgreSQL), which is absolutely essential because gathering time-related data can quickly get out of hand and snowball into huge tables which can no longer fit into memory, causing major performance issues.

To query with this language, you simply need to use the traditional SQL calls. The main nugget of information I would like to share is that querying time series-related data (example: GROUP BY), despite using a very large table — most generally a performance killer — can have similar or even faster querying (when compared to regular postgresql). This query, for example, can be up ~400x faster than a regular postgresql DB:

SELECT date_trunc(‘minute’, time) AS minute, max(usage_user)

FROM cpu

WHERE time < ‘2017–01–01’

GROUP BY minute

ORDER BY minute DESC

LIMIT 5;

The reason for this will be touched on a bit later.

OpenTSDB

When creating your DB’s schema, you can choose to base it on either HBase, BigTable, or Cassandra. Because HBase is the default, we will go over that, and because it is based on Hbase, it means all the data points are stored in a single, gigantic table. To query OpenTSDB, we can use any of the following: CLI tools, its HTTP API, and a developed GUI. A normal query with OpenTSDB uses a tag-based system which can seem quite tricky at first glance. Here’s the basic format of posting data to the DB:

<metricID><normalized_timestamp><tagkID1><tagvID1>[…<tagkIDN><tagvIDN>]

Here’s what sending some actual data looks like:

put http.hits 1578533444819 34877 host=A

put proc.loadavg.1min 1578533444819 1.35 host=A

Unlike the other Time Series Databases on this list, this one does not use a query system that resembles anything remotely looking like SQL. Instead, querying is done using tags.

Here’s the equivalent to a SELECT * from <column>. This is the easiest query to make:

m=sum:cpu.system

To further specify a tag, for example adding a specific machine/tag, you simply append to the original query:

m=sum:cpu.system{host=web01}

As for a more nuanced query, here’s one that will provide data from two different host names, separated out by group:

m=sum:cpu.nice{host=web01|web02}

Output:

[

{

“metric”: “cpu.system”,

“tags”: {

“host”: “web01”

},

“aggregated_tags”: [],

“tsuids”: [

“010101”,

“0101010306”,

“0102040101”,

“0102050101”

],

“dps”: {

“1346846400”: 63.59999942779541

}

},

{

“metric”: “cpu.system”,

“tags”: {

“host”: “web02”

},

“aggregated_tags”: [

“dc”

],

“tsuids”: [

“0102040102”,

“0102050102”

],

“dps”: {

“1346846400”: 24.199999809265137

}

}

]

GridDB

GridDB’s default usage comes from using Java to write small functions which call directly to GridDB; this can be seen in the official GitHub samples. If Java isn’t necessarily your preference, GridDB has connectors for various other programming languages (C++, Go, JavaScript/Nodejs, Perl, PHP, Python, Ruby). Because Python seems to be a very popular connector (based on GitHub stars), we will focus on that.

Once your .py file properly connects to your DB, creating a new GridDB Container (think of a container as similar to a RDB table) is simply just creating a Python object with your intended schema:

conInfo = griddb.ContainerInfo(“point01”,

[[“timestamp”, griddb.Type.TIMESTAMP],

[“active”, griddb.Type.BOOL],

[“voltage”, griddb.Type.DOUBLE]],

griddb.ContainerType.TIME_SERIES, True)

ts = gridstore.put_container(conInfo)

Now let’s PUT some data to query:

now = datetime.datetime.utcnow()

ts.put([now, False, 100])

And now let’s use GridDB’s simplified version of SQL, TQL:

query = ts.query(“select * where timestamp > TIMESTAMPADD(HOUR, NOW(), -6)”)

And then to execute and iterate through the results:

rs = query.fetch() #Get result

while rs.has_next():

data = rs.next()

timestamp = str(data[0])

active = data[1]

voltage = data[2]

print(“Time={0} Active={1} Voltage={2}”.format(timestamp, active, voltage))

To execute your GridDB code, you would just run your python file. This workflow will be very similar for whichever programming language is used.

Time Series

Next I want to explore the specific time series functionality introduced by each different database.

InfluxDB

InfluxDB differs from traditional RDBMS in that it uses a narrow-table model with the timestamp being the primary key. This non-traditional data model is designed with an easy-to-get-started with time series dataset in mind. The main advantage of having a data model that does not have a strict schema is that if the incoming data already naturally fits into the predetermined data model, it is extremely easy to get up and running; and indeed, most data in this field will naturally fit into this data model without any extra initial set up by the developer.

This database also contains special time-based query abilities. If you wanted to query for data that occurred within the past hour, for example, it would look like this:

SELECT * FROM “foodships” WHERE time > now() — 1h

To add to that, InfluxDB also includes COUNT, MIN, MAX, time_bucket, first, last, and more. It can also be used to query geospatial data types combined with time-series analytics.

Another thing worth mentioning is that the UPDATE & DELETE portions of the traditional “CRUD” (Create, Read, Update, Delete) are toned down a ton to keep CREATE and READ more performant; this is done specifically because of what TSDBs typically prioritize.

TimescaleDB

Because it’s built on top of PostgreSQL, TimescaleDB offers all of the functionality of SQL while also adding time-specific functionality. For example, there are now built in functions for median/percentile, cumulative sum, moving averages, and many more.

TimescaleDB’s data retention policy is unique in that it will delete data at the chunk level. The “chunk level” refers to the automatic chunking of like-data (generally corresponding to specific time intervals and regions of the partitions keys’ space). Essentially, TimescaleDB is able to query the entirety of its large datasets because all of it is stored on a really, really big table (hypertable); all user interaction and querying of “other”/smaller tables are just an abstraction: chunking. It is precisely through this process that TimescaleDB can claim much higher rates of ingestion over traditional relational systems.

Nearly every time series database has specific abilities to query data with time-related parameters; one of the most common of these is sum/aggregate. In TimescaleDB, we can not only aggregate, but we can do a continuous aggregate, which helps a ton with performance. Essentially, this recomputes the query automatically at specified time intervals and sets the results into a new table — when the user queries that dataset, TimescaleDB can easily and efficiently query that new made table. Of course, beyond that, there are many more features such as working with popular PostgreSQL extensions, PostGIS, for example.

OpenTSDB

The best features of OpenTSDB are its flexibility and ingest performance, mostly stemming from its foundation of HBase. Because of its HBase base, this TSDB has no schema and can ingest millions of data per second without sacrificing granularity. From the CAP theorem perspective, this is the only DB on this list that is AP (Availability, Partitioning).

On that same token though, because of its HBase foundation, this TSDB may have the biggest and more fear-inducing learning curve, which is absolutely something to consider when thinking of making that plunge. For example, in the previous section, we already saw just how different interacting with this DB is when compared to the other ones on this same list.

As for some unique time-specific features: it scales extremely well, it has very nice downscaling abilities, and has a robust tags and metrics system to easily mark the various data being stored by the DB.

GridDB

GridDB’s unique key-container data model is using the Wide-table model, which can be closely compared to a traditional relational data model, complete with having a fixed schema. With this model, it has the timestamp as the primary key of the row, allowing all columns (tags) to be associated with each time slot.

While not completely built on the relational data model, the key-container data model is relatively close; from a cap theorem perspective, GridDB fits into CP paradigm (ACID compliant). The key (usually a sensor name) will its “value” as a container, which is essentially a rdbms table, of either the time-type, or collection-type. With the collection type, it’s mostly used for metadata, even including all sensor names as an array. And with the time series container, it’ll give each sensor its own rdbms table to store all relevant information.

GridDB can also scale linearly. According to their own benchmarks, the performance of the DB will linearly scale when adding extra nodes/extra hardware. This means that on top of the fast in-memory performance, throwing more compute power will almost always increase productivity, should the need arise.

And of course, like the other TSDBs on this list, GridDB has special time functionality such as data aggregation, data retention policies, and sampling/interpolation functions. It also has some advanced time series data placement algorithms in place for maximum performance.

Conclusion

Now of course, each TSDB has its own unique set of pros and cons. Let’s briefly touch on them here:

InfluxDB

Pros: Easy to get up and running. Good performance for one node

Cons: No strict schema can be seen as a detriment. Only one node in open source.

TimeScaleDB

Pros: Full SQL, fast ingest, fixed schema

Cons: fixed schema

Note: I list “fixed schema” as both a pro and a con, because — like many things — it has many tradeoffs. If you want to hit the ground running and expand aggressively, a fixed schema can be a detriment. But if you are ok with planning out your schema and making sure all incoming data fits the schema, having ACID compliance can be worth the extra effort.

OpenTSDB

Pros: Very scalable, very fast ingest

Cons: (very) difficult learning curve, no fixed schema, interface (telnet) too different

GridDB

Pros: very performant, fixed schema, scales out linearly

Cons: fixed schema

Of course, you should always be picking your new TSDB based on your specific use case and needs.