Packages
rocksdb
2.3.0
3.1.1
3.1.0
3.0.0
2.6.2
2.6.1
retired
2.6.0
retired
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.0
0.26.2
0.26.1
0.26.0
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
RocksDB for Erlang
Current section
Files
Jump to
Current section
Files
guides/statistics.md
# RocksDB Statistics Guide
This guide explains how to collect and use RocksDB statistics in Erlang RocksDB. Statistics provide insights into database performance, I/O operations, cache efficiency, and more.
## Getting Started
### Creating a Statistics Object
First, create a statistics object and attach it to your database:
```erlang
%% Create a statistics collector
{ok, Stats} = rocksdb:new_statistics(),
%% Open database with statistics enabled
{ok, Db} = rocksdb:open("my_db", [
{create_if_missing, true},
{statistics, Stats}
]).
```
### Reading Statistics
Use `rocksdb:statistics_ticker/2` to read counter values:
```erlang
{ok, KeysWritten} = rocksdb:statistics_ticker(Stats, number_keys_written),
io:format("Keys written: ~p~n", [KeysWritten]).
```
Use `rocksdb:statistics_histogram/2` to read histogram data:
```erlang
{ok, WriteHist} = rocksdb:statistics_histogram(Stats, db_write),
io:format("Write latency - median: ~.2f us, p99: ~.2f us~n",
[maps:get(median, WriteHist), maps:get(percentile99, WriteHist)]).
```
### Histogram Data Format
Histogram results are returned as a map with the following keys:
| Key | Type | Description |
|-----|------|-------------|
| `median` | float | 50th percentile value |
| `percentile95` | float | 95th percentile value |
| `percentile99` | float | 99th percentile value |
| `average` | float | Mean value |
| `standard_deviation` | float | Standard deviation |
| `max` | float | Maximum observed value |
| `count` | integer | Number of samples |
| `sum` | integer | Sum of all samples |
### Setting Statistics Level
Control the level of detail collected:
```erlang
%% Set to collect all statistics
ok = rocksdb:set_stats_level(Stats, stats_all),
%% Or disable expensive timing stats
ok = rocksdb:set_stats_level(Stats, stats_except_timers).
```
Available levels:
- `stats_disable_all` - Disable all statistics
- `stats_except_tickers` - Collect histograms only
- `stats_except_histogram_or_timers` - Collect tickers only (no histograms or timing)
- `stats_except_timers` - Collect everything except timing measurements
- `stats_except_detailed_timers` - Collect everything except detailed timing
- `stats_except_time_for_mutex` - Collect everything except mutex timing
- `stats_all` - Collect all statistics (default)
### Cleanup
Release the statistics object when done:
```erlang
ok = rocksdb:close(Db),
ok = rocksdb:release_statistics(Stats).
```
---
## Complete Ticker Reference
Tickers are simple counters that track cumulative values.
### Database Operation Tickers
| Ticker | Description |
|--------|-------------|
| `number_keys_written` | Total number of keys written to the database |
| `number_keys_read` | Total number of keys read from the database |
| `number_keys_updated` | Total number of keys updated (via merge) |
| `bytes_written` | Total bytes written to the database |
| `bytes_read` | Total bytes read from the database |
| `iter_bytes_read` | Total bytes read through iterators |
### Iterator Tickers
| Ticker | Description |
|--------|-------------|
| `number_db_seek` | Number of seek operations on iterators |
| `number_db_next` | Number of next operations on iterators |
| `number_db_prev` | Number of prev operations on iterators |
| `number_db_seek_found` | Number of seek operations that found a key |
| `number_db_next_found` | Number of next operations that found a key |
| `number_db_prev_found` | Number of prev operations that found a key |
### Block Cache Tickers
| Ticker | Description |
|--------|-------------|
| `block_cache_miss` | Total block cache misses |
| `block_cache_hit` | Total block cache hits |
| `block_cache_add` | Number of blocks added to cache |
| `block_cache_add_failures` | Number of failures adding blocks to cache |
| `block_cache_index_miss` | Index block cache misses |
| `block_cache_index_hit` | Index block cache hits |
| `block_cache_filter_miss` | Filter block cache misses |
| `block_cache_filter_hit` | Filter block cache hits |
| `block_cache_data_miss` | Data block cache misses |
| `block_cache_data_hit` | Data block cache hits |
| `block_cache_bytes_read` | Total bytes read from block cache |
| `block_cache_bytes_write` | Total bytes written to block cache |
**Example - Calculate cache hit ratio:**
```erlang
{ok, Hits} = rocksdb:statistics_ticker(Stats, block_cache_hit),
{ok, Misses} = rocksdb:statistics_ticker(Stats, block_cache_miss),
HitRatio = case Hits + Misses of
0 -> 0.0;
Total -> Hits / Total * 100
end,
io:format("Block cache hit ratio: ~.2f%~n", [HitRatio]).
```
### Memtable Tickers
| Ticker | Description |
|--------|-------------|
| `memtable_hit` | Number of reads served from memtable |
| `memtable_miss` | Number of reads not found in memtable |
### Write Path Tickers
| Ticker | Description |
|--------|-------------|
| `write_done_by_self` | Writes completed by the calling thread |
| `write_done_by_other` | Writes batched and completed by another thread |
| `wal_file_synced` | Number of WAL file sync operations |
| `stall_micros` | Total microseconds spent in write stalls |
### Compaction Tickers
| Ticker | Description |
|--------|-------------|
| `compact_read_bytes` | Bytes read during compaction |
| `compact_write_bytes` | Bytes written during compaction |
| `flush_write_bytes` | Bytes written during memtable flush |
| `compaction_key_drop_newer_entry` | Keys dropped due to newer version existing |
| `compaction_key_drop_obsolete` | Keys dropped due to being obsolete (deleted) |
| `compaction_key_drop_range_del` | Keys dropped due to range delete |
| `compaction_key_drop_user` | Keys dropped by user compaction filter |
| `compaction_cancelled` | Number of cancelled compactions |
| `number_superversion_acquires` | Superversion acquire operations |
| `number_superversion_releases` | Superversion release operations |
### BlobDB Tickers
| Ticker | Description |
|--------|-------------|
| `blob_db_num_put` | Number of put operations |
| `blob_db_num_write` | Number of write operations |
| `blob_db_num_get` | Number of get operations |
| `blob_db_num_multiget` | Number of multi-get operations |
| `blob_db_num_seek` | Number of seek operations |
| `blob_db_num_next` | Number of next operations |
| `blob_db_num_prev` | Number of prev operations |
| `blob_db_num_keys_written` | Number of keys written |
| `blob_db_num_keys_read` | Number of keys read |
| `blob_db_bytes_written` | Total bytes written |
| `blob_db_bytes_read` | Total bytes read |
| `blob_db_write_inlined` | Writes stored inline (not in blob) |
| `blob_db_write_inlined_ttl` | Inline writes with TTL |
| `blob_db_write_blob` | Writes stored in blob files |
| `blob_db_write_blob_ttl` | Blob writes with TTL |
| `blob_db_blob_file_bytes_written` | Bytes written to blob files |
| `blob_db_blob_file_bytes_read` | Bytes read from blob files |
| `blob_db_blob_file_synced` | Number of blob file syncs |
| `blob_db_blob_index_expired_count` | Expired blob index entries |
| `blob_db_blob_index_expired_size` | Size of expired blob index entries |
| `blob_db_blob_index_evicted_count` | Evicted blob index entries |
| `blob_db_blob_index_evicted_size` | Size of evicted blob index entries |
| `blob_db_gc_num_files` | Blob files processed by GC |
| `blob_db_gc_num_new_files` | New blob files created by GC |
| `blob_db_gc_failures` | Number of GC failures |
| `blob_db_gc_num_keys_relocated` | Keys relocated during GC |
| `blob_db_gc_bytes_relocated` | Bytes relocated during GC |
| `blob_db_fifo_num_files_evicted` | Files evicted by FIFO compaction |
| `blob_db_fifo_num_keys_evicted` | Keys evicted by FIFO compaction |
| `blob_db_fifo_bytes_evicted` | Bytes evicted by FIFO compaction |
| `blob_db_cache_miss` | Blob cache misses |
| `blob_db_cache_hit` | Blob cache hits |
| `blob_db_cache_add` | Blobs added to cache |
| `blob_db_cache_add_failures` | Failed blob cache additions |
| `blob_db_cache_bytes_read` | Bytes read from blob cache |
| `blob_db_cache_bytes_write` | Bytes written to blob cache |
### Transaction Tickers
| Ticker | Description |
|--------|-------------|
| `txn_prepare_mutex_overhead` | Time spent waiting on prepare mutex (ns) |
| `txn_old_commit_map_mutex_overhead` | Time spent waiting on commit map mutex (ns) |
| `txn_duplicate_key_overhead` | Time spent on duplicate key checking (ns) |
| `txn_snapshot_mutex_overhead` | Time spent waiting on snapshot mutex (ns) |
| `txn_get_try_again` | Number of TryAgain errors from transaction gets |
---
## Complete Histogram Reference
Histograms track the distribution of values over time.
### Database Operation Histograms
| Histogram | Description |
|-----------|-------------|
| `db_get` | Get operation latency (microseconds) |
| `db_write` | Write operation latency (microseconds) |
| `db_multiget` | Multi-get operation latency (microseconds) |
| `db_seek` | Iterator seek latency (microseconds) |
**Example - Monitor read latency:**
```erlang
{ok, GetHist} = rocksdb:statistics_histogram(Stats, db_get),
io:format("Get latency:~n"),
io:format(" Median: ~.2f us~n", [maps:get(median, GetHist)]),
io:format(" P95: ~.2f us~n", [maps:get(percentile95, GetHist)]),
io:format(" P99: ~.2f us~n", [maps:get(percentile99, GetHist)]),
io:format(" Max: ~.2f us~n", [maps:get(max, GetHist)]).
```
### Compaction and Flush Histograms
| Histogram | Description |
|-----------|-------------|
| `compaction_time` | Compaction duration (microseconds) |
| `flush_time` | Memtable flush duration (microseconds) |
### I/O Histograms
| Histogram | Description |
|-----------|-------------|
| `sst_read_micros` | SST file read latency (microseconds) |
| `sst_write_micros` | SST file write latency (microseconds) |
| `table_sync_micros` | SST file sync latency (microseconds) |
| `wal_file_sync_micros` | WAL file sync latency (microseconds) |
| `bytes_per_read` | Bytes per read operation |
| `bytes_per_write` | Bytes per write operation |
### BlobDB Histograms
| Histogram | Description |
|-----------|-------------|
| `blob_db_key_size` | Key size distribution (bytes) |
| `blob_db_value_size` | Value size distribution (bytes) |
| `blob_db_write_micros` | Write latency (microseconds) |
| `blob_db_get_micros` | Get latency (microseconds) |
| `blob_db_multiget_micros` | Multi-get latency (microseconds) |
| `blob_db_seek_micros` | Seek latency (microseconds) |
| `blob_db_next_micros` | Next latency (microseconds) |
| `blob_db_prev_micros` | Prev latency (microseconds) |
| `blob_db_blob_file_write_micros` | Blob file write latency (microseconds) |
| `blob_db_blob_file_read_micros` | Blob file read latency (microseconds) |
| `blob_db_blob_file_sync_micros` | Blob file sync latency (microseconds) |
| `blob_db_compression_micros` | Compression time (microseconds) |
| `blob_db_decompression_micros` | Decompression time (microseconds) |
### Transaction Histograms
| Histogram | Description |
|-----------|-------------|
| `num_op_per_transaction` | Number of operations per transaction |
---
## Example: Comprehensive Monitoring
Here's a complete example that monitors key database metrics:
```erlang
-module(db_monitor).
-export([report/1]).
report(Stats) ->
%% Operation counts
{ok, KeysWritten} = rocksdb:statistics_ticker(Stats, number_keys_written),
{ok, KeysRead} = rocksdb:statistics_ticker(Stats, number_keys_read),
%% Cache efficiency
{ok, CacheHits} = rocksdb:statistics_ticker(Stats, block_cache_hit),
{ok, CacheMisses} = rocksdb:statistics_ticker(Stats, block_cache_miss),
CacheHitRatio = safe_ratio(CacheHits, CacheHits + CacheMisses),
%% Memtable efficiency
{ok, MemHits} = rocksdb:statistics_ticker(Stats, memtable_hit),
{ok, MemMisses} = rocksdb:statistics_ticker(Stats, memtable_miss),
MemHitRatio = safe_ratio(MemHits, MemHits + MemMisses),
%% Write stalls
{ok, StallMicros} = rocksdb:statistics_ticker(Stats, stall_micros),
%% Latency histograms
{ok, GetHist} = rocksdb:statistics_histogram(Stats, db_get),
{ok, WriteHist} = rocksdb:statistics_histogram(Stats, db_write),
io:format("=== RocksDB Statistics ===~n"),
io:format("Keys written: ~p, Keys read: ~p~n", [KeysWritten, KeysRead]),
io:format("Block cache hit ratio: ~.2f%~n", [CacheHitRatio * 100]),
io:format("Memtable hit ratio: ~.2f%~n", [MemHitRatio * 100]),
io:format("Total stall time: ~.2f ms~n", [StallMicros / 1000]),
io:format("Get latency p99: ~.2f us~n", [maps:get(percentile99, GetHist)]),
io:format("Write latency p99: ~.2f us~n", [maps:get(percentile99, WriteHist)]),
ok.
safe_ratio(_, 0) -> 0.0;
safe_ratio(Num, Denom) -> Num / Denom.
```
---
## Statistics with Column Families
When using column families, create one statistics object and share it:
```erlang
{ok, Stats} = rocksdb:new_statistics(),
{ok, Db, [DefaultCf, DataCf, IndexCf]} = rocksdb:open_with_cf(
"my_db",
[{create_if_missing, true}, {statistics, Stats}],
[{"default", []}, {"data", []}, {"index", []}]
),
%% Statistics are aggregated across all column families
{ok, TotalKeysWritten} = rocksdb:statistics_ticker(Stats, number_keys_written).
```
---
## Statistics with Transactions
Statistics also work with pessimistic transaction databases:
```erlang
{ok, Stats} = rocksdb:new_statistics(),
{ok, Db, _} = rocksdb:open_pessimistic_transaction_db(
"txn_db",
[{create_if_missing, true}, {statistics, Stats}],
[{"default", []}]
),
%% Perform transactions...
{ok, Txn} = rocksdb:pessimistic_transaction(Db, []),
ok = rocksdb:pessimistic_transaction_put(Txn, <<"key">>, <<"value">>),
ok = rocksdb:pessimistic_transaction_commit(Txn),
ok = rocksdb:release_pessimistic_transaction(Txn),
%% Check transaction-specific stats
{ok, OpsPerTxn} = rocksdb:statistics_histogram(Stats, num_op_per_transaction),
io:format("Avg ops per transaction: ~.2f~n", [maps:get(average, OpsPerTxn)]).
```
---
## Performance Considerations
1. **Statistics overhead**: Collecting statistics has a small performance cost. Use `stats_except_timers` or `stats_except_detailed_timers` in production if timing precision isn't critical.
2. **Polling frequency**: Statistics are cumulative. Poll them periodically and compute deltas for rate metrics.
3. **Memory**: The statistics object uses minimal memory but should be released when no longer needed.
4. **Thread safety**: Statistics are thread-safe and can be read from any Erlang process.