Storing Billions of VM Metrics with TimescaleDB
Tags: timescaledb, postgres, programming, startup
Published: 2022-10-25 19:07:02

Originally published [here](https://webapp.io/blog/storing-millions-of-vm-metrics-with-timescaledb/).

With the recent launch of our Layerfile analytics project, we encountered a cool engineering problem - how to store billions of virtual machine (VM) metrics in PostgreSQL.

**The problem**

With the recent launch of our [Layerfile analytics project](https://docs.webapp.io/advanced-workflows/layerfile-analytics), we encountered a cool engineering problem - how to store billions of [virtual machine](https://webapp.io/blog/the-difference-between-vms-and-containers/) (VM) metrics in [PostgreSQL](https://webapp.io/blog/postgres-is-the-answer/). The metrics we wanted to track were the VM's CPU, disk and memory usage at a one second interval throughout the duration of its life. Our data can be considered time-series data as it is timestamped and append only.

While [PostgreSQL](https://webapp.io/blog/postgres-is-the-answer/) will be sufficient for our first few million rows, we will start to see its performance decline as the number of writes increases and our table grows. The main pain points we faced included:

Reads and writes being too slow at scale
Threat of growing table size causing disk pressure
With these points in mind, we chose [TimescaleDB](https://www.timescale.com/).

**What is TimescaleDB?**

TimescaleDB is a time-series database built on top of PostgreSQL. It is an extension to PostgreSQL that implements tools to aide in the handling and processing of [time-series data](https://www.influxdata.com/what-is-time-series-data/). The Timescale extension runs within a PostgreSQL server processing queries first to determine the planning and execution of queries involving time-series data. This enables much higher data ingestion rates and greatly improves query performance.



![Ingest Rate: PostgreSQL vs Timescale Source: https://docs.timescale.com/timescaledb/latest/overview/how-does-it-compare/timescaledb-vs-postgres/](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0wwz1q78gf2a88fkijw7.jpeg)

**How we used Timescale to solve our problem**

The first step taken was to convert the table storing our metrics into a [Hypertable](https://docs.timescale.com/timescaledb/latest/overview/core-concepts/hypertables-and-chunks/). Hypertables look and feel like regular PostgreSQL tables but are partitioned by Timescale into time based chunks. Creating a Hypertable allows us to take advantage of Timescale's full suite of tooling in addition to the ingestion and query performance.

The next step was to create a [compression](https://docs.timescale.com/timescaledb/latest/overview/core-concepts/compression/) policy on the Hypertable. Timescale will compress chunks of data older than an interval you specify in a compression policy, in our case, 1 week. This data can still be accessed but not updated. Enabling compression on a Hypertable has between a 91-96% storage savings.

Finally, we used [continuous aggregates](https://docs.timescale.com/timescaledb/latest/overview/core-concepts/continuous-aggregates/). They are similar to PostgreSQL's [materialized views](https://www.postgresql.org/docs/current/rules-materializedviews.html) but can be refreshed using a policy. We created a continuous aggregate that averages each stat over a 15 second interval refreshing every minute. This allows us to select already processed data from a smaller table, ready to be consumed by the front end.