Persistence

Historical context

Etsy's original ("reference") implementation of statsd primarily served as a first level aggregation and passthrough of data to Graphite (http://graphite.wikidot.com) and its associated Whisper storage engine. In this case, it performs the first aggregation over the course of its flush interval (typically 10 seconds in operation) and then passes those aggregated values to Graphite to store. It does not directly provide a persistence model.

Batsd uses two datastores to store historical data.

Configuration

The configuration of retention levels is similar in concept to Graphite, and is specified in the config file:

retentions:
  10:  360 # store data at 10 second increments for 1 hour
  60:  10080  # store data at 1 minute increments for 1 week
  600: 52594 # store data at 10 minute increments for 1 year

The shortest-term aggregation is always stored in Redis; the latter ones always stored to disk. In the future, this may be configurable.

Redis persistency

Near term data stored in redis is stored in sorted sets, one per datapoint, with the Unix timestamp as the score and a string structured as #{now}<X>#{value} as the value. This does mean that the string <X> is a reserved component in Batsd, and cannot be used in any key names.

In addition to storing that sorted set, the current set of timer values is stored as a single string with expiry set to be used for later aggregations.

A cleanup process is run occasionally to truncate the sorted sets using a ZREMRANGEBYSCORE. See hisotrical truncation for details on configuring this.

Diskstore

Longer duration data is stored in flat files located within subdirectories of the root specified in the configuration file.

The location of a file will be determined by the MD5 hash of #{metric_name}:#{aggregationLevel}. Files are then stored two subdirectories deep using the first four characters of that hash.

For example, with a root of /statsd, the path for the 60 second aggregation of test_metric will be /statsd/88/b4/88b4ca597dfc2d67438cc26140b2615b.

Data is written to these files in #{timestamp} #{value} format, with each measurement separated by a \n newline character, in sequential order.