Plan receiver capacity
Size a receiver and prove it can sustain the feed before production activation.
Before you start
- A target latency budget
- Representative packet captures or live staging traffic
Establish the input budget
At the receiver, measure both packet rate and average payload bytes. Use packets per second to plan CPU and queue capacity, bytes per second for network and memory bandwidth, and monthly bytes only for retention. The wire maximum is 1,228 bytes per UDP datagram.
The worked calculation uses 5,000 datagrams per second with 1,200 mean payload bytes:
text
5,000 packets/s × 1,200 bytes × 8 = 48,000,000 bits/s5,000 packets/s × 86,400 s = 432,000,000 packets/day48 Mb/s ÷ 8 = 6 MB/s6 MB/s × 2,592,000 s = 15.552 TB per 30 daysEthernet, IP, UDP, framing, and inter-packet gaps add link overhead beyond UDP payload. Do not choose interface capacity from the example payload rate alone when bursts, monitoring, RPC, storage replication, and encapsulation share the path.
Apply independent headroom factors
For the worked example, use four times the assumed packet rate for short-window receive sizing until measurements support a different factor. That target is 20,000 packets per second and 192 Mbps of UDP payload if mean packet size remains 1,200 bytes. Use two times the observed sustained busy-window rate for worker capacity. Burst capacity and sustained capacity are different requirements.
Compute queue slots from duration:
text
slots = ceil(5,000 × 4 × 0.250 seconds) = 5,000round to implementation capacity = 8,192 packet slotsraw slot bytes = 8,192 × 1,228 = 10,059,776 bytesThen add packet metadata, allocator or slab bookkeeping, channel storage, FEC maps, slot ordering state, duplicate keys, decoded entries, and downstream messages. Measure resident memory at forced maximum queue occupancy. Avoid estimating a Rust object from field sizes alone because allocator alignment and container capacity matter.
Benchmark stages separately
Measure receive, header parse, leader lookup, signature and Merkle verification, duplicate check, FEC insertion, Reed-Solomon recovery, deshred, entry decode, transaction extraction, and downstream publication. Report items per core-second and p50, p95, and p99 execution time.
Use captured shreds with realistic duplicates, reordering, missing data, and coding ratios. A benchmark containing only complete, ordered data shreds skips the expensive error and recovery paths. Include empty tick entries and versioned transactions.
Estimate core demand from measured service time:
text
cores = arrival_rate × mean_cpu_seconds_per_item ÷ target_utilizationexample = 5,000 × 0.000050 ÷ 0.60 = 0.42 cores for a 50 microsecond stageThis example is a formula, not a claim that verification takes 50 microseconds on your CPU. Use no more than about 60 to 70 percent sustained utilization on latency-sensitive workers. Tail latency grows sharply near saturation, and FEC recovery creates uneven work.
The following small calculator keeps units explicit:
rust
fn cores(rate_per_second: f64, micros_per_item: f64, target: f64) -> f64 { rate_per_second * micros_per_item / 1_000_000.0 / target} fn queue_slots(rate: f64, burst: f64, stall_ms: f64) -> usize { (rate * burst * stall_ms / 1000.0).ceil() as usize} fn main() { let _required_cores = cores(5000.0, 50.0, 0.60); let _required_slots = queue_slots(5000.0, 4.0, 250.0);}Bound protocol state
The FEC-state key is (slot, fec_set_index). Bound active slots, active sets, shards per set, total stored packet bytes, and age. Typical current construction puts 32 data members beside 32 coding members in an FEC block. Recovery must still read both actual counts from coding headers. Shorter final sets are valid, and protocol releases can change construction.
If 128 active FEC sets each retain 64 maximum datagrams, raw packet storage is about 10 MiB. Multiple copies across queues and maps multiply that number. Store one owned packet and move ownership between stages where practical.
Bound duplicate retention by time or recent slots. Shred type, slot, and index can form the key; conflict detection also needs a payload fingerprint or canonical bytes. Clear state after the slot is no longer useful and record evictions.
Plan storage only when required
Do not write every raw datagram to the primary receiver disk by default. Calculate retention from the receiver's observed byte rate. A rotating diagnostic capture of minutes or a sampled failure capture is cheaper and safer. If full retention is required, provision sustained sequential write, metadata, compression CPU, replication, index overhead, and recovery time.
Prove headroom
Replay one hour of busy traffic at one, two, and four times original timing. Inject packet loss and reorder windows so recovery runs. Pass only if the receiver keeps kernel and application drops at zero at the promised target, queue age returns to baseline, memory stays bounded, and no worker exceeds the sustained utilization budget.
Repeat the benchmark on the actual instance type. Cloud CPU generation, steal time, NIC virtualization, NUMA placement, kernel, compiler, and Agave dependency revision can materially change results. Capacity is a tested property of the deployed system, not a property of the source code alone.
Record the benchmark inputs and build identity with every result. A throughput number without the capture digest, replay timing, loss pattern, CPU allocation, and binary revision cannot support the next capacity decision.
Parameters
When it goes wrong
benchmark passes ordered data but fails live traffic
Cause. The test omitted duplicates, reordering, signature work, or Reed-Solomon recovery.
Fix. Replay representative captured traffic and inject recoverable and unrecoverable loss.
CPU remains below 50 percent but queue age grows
Cause. One partition or single-threaded stage is saturated while aggregate CPU hides it.
Fix. Measure per-thread utilization, queue age, and key distribution, then repartition the constrained stage.
disk fills near day 2
Cause. Raw retention was sized from an incorrect decimal, duration, or compression assumption.
Fix. Calculate 30-day retention from receiver byte counts before replication and filesystem overhead.
Questions
- Why plan for four times the average packet rate?
- The one-second average hides leader emission patterns, network queue compression, and scheduler pauses. Four times is a conservative starting point for short windows, not a measured maximum. Record 1, 10, and 100 millisecond rates in production and replace the factor with observed percentiles.
- How much disk does full raw retention need?
- Multiply the observed receiver byte rate by the retention period, then add filesystem metadata, indexes, replicas, and backups. Compression depends on the data and costs CPU. Most low-latency receivers should keep bounded diagnostic captures unless complete raw retention is a stated product requirement.
- Can one CPU core receive the feed?
- Receipt is only the first stage. Measure signature verification separately, then recovery, entry decoding, and downstream publication. Benchmark every stage on the deployment host and retain utilization headroom for bursty recovery.