A billion metrics a second.* Right inside PostgreSQL.
Stop running separate time-series databases, external aggregator daemons, and fragile synchronization pipelines just to count events. stat_pg embeds a StatsD-inspired high-speed metric ingestion engine directly into PostgreSQL as a native background worker.
PostgreSQL is already your database. Why run a separate one just for metrics?
Modern application architecture has fallen into a trap: the moment metric volume grows, teams reach for an entirely separate distributed time-series database. Here is what that tax actually looks like.
What Most Teams Build
- Spin up a separate TSDB cluster (InfluxDB, Prometheus, VictoriaMetrics, ClickHouse).
- Deploy and maintain external aggregator daemons (StatsD, Telegraf, Vector) on every VM.
- Deal with two backup systems, two monitoring planes, and two sets of operational runbooks.
- Cannot perform native SQL joins between metrics and production application data.
- Network hops, dual-write failures, and eventual consistency lag across cluster boundaries.
What It Looks Like Inside PostgreSQL
- One binary extension running directly in PostgreSQL's native process space.
- Listen on port 8125 using high-speed UDP or eBPF kernel network bypass.
- Aggregate billions of metrics in-memory using lock-free double-buffered rings.*
- Transaction-safe cascading rollups into clean SQL tables (
stat_pg_secs,mins,hours,days). - Instant
JOINcapability with your actual users, tenants, and business entities in standard SQL.
Almost nobody actually needs to ingest a billion metrics every second.
So why push stat_pg to physical hardware saturation? Because extreme mechanical efficiency trickles down to modest hardware.
If telemetry software requires a heavy multi-node cluster just to handle a few hundred thousand events, it is wasting compute. But when an engine is engineered to persist over a billion metrics per second on modern silicon, it means that a modest home lab server, an edge IoT gateway, or a $35 Raspberry Pi can easily chew through millions of metrics per second with negligible CPU usage and near-zero memory footprint. You get enterprise-scale telemetry throughput without the enterprise cloud bill.
While stat_pg is designed to run directly inside your existing PostgreSQL database alongside your production tables, your mileage may vary depending on ingestion volume. If you require extremely high-speed ingestion—such as massive streams of continuous IoT telemetry or saturating multi-gigabit NICs—the background workers, kernel buffers, and unlogged staging merges share CPU execution ports and memory bus bandwidth with your application's queries.
Test your specific read and write patterns under load. If high-speed ingestion impacts primary application transaction latency, consider running stat_pg on its own dedicated PostgreSQL instance.
Engineered for pure hardware saturation.
Reaching a billion metrics a second inside a relational database requires relentless mechanical sympathy. Every layer of stat_pg was profiled, torn down, and rebuilt until the hardware had nothing left to give.
eBPF XDP Kernel Bypass
Intercepts raw network frames directly at the NIC driver before the Linux kernel allocates an sk_buff. Wire metrics accumulate in lock-free per-CPU BPF maps at 13.03 GB/sec.[2]
Lock-Free Double Buffering
Network receiver threads write directly to a shared memory buffer. Every second, the database writer swaps buffers in a sub-microsecond atomic operation. Network ingestion never waits on disk I/O.
Hierarchical Cascading Rollups
Background workers write only to high-resolution second tables. Minute, hour, and day rollups are lazily computed on epoch boundaries, dropping transaction merge latency by 6x.
SIMD Vectorized Decoding
Network payloads pack updates into branchless columnar segments. Receiver loops decode 16 variable-width metric formats using SIMD vector instructions with zero branch mispredictions.
RAM-Backed Unlogged Staging
Workers stream buffer snapshots into /dev/shm and load via PostgreSQL COPY into unlogged staging tables, avoiding WAL write-amplification entirely.
Sequential B-Tree Inserts
Coordinator merge queries enforce ORDER BY at, metric_id. Rows enter database indexes in strict sequential order, eliminating page splits and keeping index leaves compact.
Massive Storage Space Savings
Because metrics are aggregated in-memory into temporal buckets, storage scales with unique metric IDs, not raw event volume. In eBPF stress tests, 2.15 trillion metrics consumed only 1.16 MB of database table disk space.[3]
stat_pg opens a raw UDP socket (default port 8125) directly within the PostgreSQL database process space. To eliminate parsing stalls and achieve line-rate wire throughput with kernel bypass, this port is completely unauthenticated and unencrypted.
While a production database should never be exposed directly to the public internet, engineering teams must remain mindful of this extra network exposure even inside private subnets, VPCs, and internal networks. Any device capable of sending UDP packets to port 8125 can increment metric values.
stat_pg is currently in an early alpha stage. Native authentication or encryption mechanisms are not currently supported, though they may be added in future revisions. Architectural proposals for locking down the ingestion ingress without sacrificing raw hardware performance are warmly welcomed.
stat_pg does not introduce new ports to firewall on the public web, new query syntaxes to learn, or background agents to babysit. If you know PostgreSQL and UDP, you already know how to run, scale, and query stat_pg.
Up and running in thirty seconds.
Add stat_pg to your PostgreSQL cluster, blast metrics over standard UDP, and query your live telemetry in real-time.
# 1. Add stat_pg to postgresql.conf and restart Postgres
shared_preload_libraries = 'stat_pg'
stat_pg.workers = 4
stat_pg.port = 8125
# 2. In psql, initialize the extension
CREATE EXTENSION stat_pg;
# 3. Fire metrics over standard UDP (StatsD line protocol or binary)
$ echo "api.search.latency:42|ms" | nc -u -w0 127.0.0.1 8125
$ echo "user.signup.count:1|c" | nc -u -w0 127.0.0.1 8125
# 4. Query rollup tables immediately using standard SQL
SELECT
m.name,
s.at,
s.value
FROM stat_pg_secs s
JOIN stat_pg_metrics m ON m.id = s.metric_id
ORDER BY s.at DESC;
Curious how I pushed it to 1.14 billion metrics/sec?
Read the step-by-step engineering journey reconstructed directly from git logs and flamegraphs.
Benchmark Environment & Performance Disclosures
Test Machine & Operating System: All performance benchmarks, throughput tests, and flamegraph profiles cited on this website were executed on a 2026 MacBook Pro with an M5 Max Chip. The benchmark harness ran within a Linux Docker container on macOS Tohoe.
Throughput & Bandwidth Context:
[1] Total Throughput (1.147B MPS sustained persistence): Measured using client-side local pre-aggregation and MTU packet stuffing (stat_pg_bench --local-agg). Updates are accumulated locally per second across 64 sender threads before being sent in dense binary multi-segment payloads over UDP into PostgreSQL background workers. Metrics are staged into RAM-backed unlogged tables and committed to resolution tables via sequential B-Tree merges.
[2] Network Bandwidth (13.03 GB/s & 9.50M UDP Packets/sec wire blast): Measured over the local container virtual network interface using the eBPF XDP kernel network bypass driver (stat_pg_xdp.bpf.c). The driver hooks directly into the network interface to intercept raw Ethernet frames before Linux allocates kernel sk_buff structures, incrementing lock-free per-CPU BPF maps in place. Over external physical networks, throughput is naturally constrained by physical NIC and switch link speeds (e.g., 10 GbE / 25 GbE / 100 GbE).
[3] Storage Space Efficiency (1.16 MB for 2.15T metrics): Measured during eBPF XDP verification testing. Because stat_pg aggregates events in memory into fixed temporal buckets (seconds, minutes, hours, days) rather than storing discrete event logs, storage scales as O(unique metrics × time intervals) rather than O(raw events). Storing 2.15 trillion discrete unaggregated events at an industry standard of 50–100 bytes each would otherwise require 100 to 200 Terabytes of disk space. On the wire, 2-byte metric IDs and columnar packing reduce payload overhead to 2.49 bytes per update.
[4] Maximum Observed Storage Efficiency: This represents the maximum observed efficiency achieved with the most efficient metric type. Mixed metrics (such as timers, gauges, or sets) may have different storage requirements, but the overhead is still extreme in its efficiency.