Performance
Fanout has a publication candidate, not an official throughput claim yet. The distinction is visible beside the number because provenance is part of a benchmark result, not a footnote added after it.
Candidate result
Section titled “Candidate result”On a machine with eight logical CPUs and 15.6 GiB of memory, Fanout v2026.8.11 accepted 296,196 OpenTelemetry items per second for five minutes. The load contained traces, logs and metrics at the same time, and Fanout and the load generators shared the host.
| Workload | Fanout accepted/s | Offered/s | Average Fanout CPU | Peak RSS |
|---|---|---|---|---|
| Traces, spans | 220,324 | 320,000 | 2.45 cores | 1.2 GiB |
| Logs, records | 187,303 | 320,000 | 3.04 cores | 1.3 GiB |
| Metrics, data points | 209,638 | 320,000 | 1.69 cores | 1.1 GiB |
| Three-signal short peak | 355,938 | 960,000 | 4.57 cores | 3.0 GiB |
| Three-signal sustained | 296,196 | 960,000 | 4.90 cores | 9.4 GiB |
Accepted throughput is the change in Fanout’s own
fanout_ingest_rows_total counter over the measured phase. It is not the rate
requested or reported by the generator. Across the complete saturation suite,
Fanout accepted 153.8 million items.
The run passed its functional quality gates: every generator exited
successfully, Fanout reported zero dropped rows and no restart, and fanout repair verify validated the authoritative Parquet store.
Generator load, not a Fanout scaling curve
Section titled “Generator load, not a Fanout scaling curve”The chart on the landing page plots the same run’s generator sweep: one, two,
four, eight and sixteen telemetrygen processes per signal, doubling at every
step. Accepted throughput rose from 38,853 items per second at one process per
signal to the 355,938 short peak at sixteen. That is a 9.2x gain for a 16x
increase in generators, and the shape is the point—below sixteen processes the
load generators, not Fanout, set the rate. Read it as evidence that the
saturating configuration was reached, not as a scaling law for Fanout itself.
The intermediate process counts are plotted from the same run and their exact
values ship with the raw artifacts.
What this number does—and does not—measure
Section titled “What this number does—and does not—measure”This is a three-signal ingest result: spans, log records and metric data points were written concurrently. It is not a read/write result. Calling it a mixed workload would imply that dashboard queries ran beside ingest, which they did not.
The official read-under-write result will separately report requested, completed, failed and shed query rates plus p50, p95 and p99 latency. Until that result passes, Fanout makes no claim about interactive query capacity at the headline write rate.
The generators shared the Fanout host, so generator CPU and memory contention
can make the observed result lower than an isolated-server ceiling. Synthetic
telemetrygen payloads are also highly compressible, so this run is not a
storage-sizing formula for production data.
What the official result must carry
Section titled “What the official result must carry”Before the candidate becomes Fanout’s official headline, it has to ship with:
- the Fanout release artifact and checksum plus the benchmark-driver commit;
- complete machine, network, container and Fanout configuration;
- the raw
report.json,report.mdandsamples.jsonlfrom that same run; - an authenticated OTLP path matching the current release;
- at least three publish-preset repetitions and their variability;
- separate ingest-only and read-under-write results;
- the query completion rate and latency distribution beside any read claim;
- limitations stated next to the result rather than hidden at the bottom.
Reproduce it on your hardware
Section titled “Reproduce it on your hardware”The independent
Fanout Bench project drives the
official OpenTelemetry telemetrygen client, counts rows accepted by Fanout,
and emits raw JSON plus a publication-ready report. It can add authenticated
dashboard reads on top, which is the part that matters.
Parquet ingest, indexed trace reads, and DuckDB analytics have separate
coordination paths, but they still compete for the same CPU, memory bandwidth,
filesystem cache, and disk. Maintenance adds native Parquet merge work and
short reader-exclusive namespace changes. An ingest-only number therefore
still overstates what an instance does while anyone is looking at it.
Create a short-lived ingest token through first-admin setup, configure Fanout
with a dedicated FANOUT_METRICS_TOKEN, then expose that same metrics token to
the harness as FANOUT_BENCH_METRICS_TOKEN. Metrics are private by default. A
local run starts with:
export FANOUT_BENCH_INGEST_TOKEN='…'export FANOUT_BENCH_METRICS_TOKEN='…'fanout-bench run \ --endpoint localhost:4317 \ --metrics-url http://localhost:7520/-/metrics \ --insecure \ --same-hostThe harness repository documents signal-specific saturation, sustained
three-signal load, read-under-write latency, machine identity, and publication
rules. For a publication-quality run, use the publish preset and retain all
three repetitions:
fanout-bench run \ --host your-benchmark-host \ --fanout-version v2026.8.11 \ --preset publish \ --repeat 3 \ --output results/fanout-v2026.8.11What to watch in production
Section titled “What to watch in production”For capacity, the useful signals are the ones an instance emits about itself: telemetry drops, sustained query latency, readiness failures, and free disk. Troubleshooting lists where they are.