Architecting Zero-Allocation Telemetry System
Video Walkthrough & Architecture Breakdown
The Challenge
At target ingest rate, off-the-shelf databases and hyperscaler managed services carried over $4,000,000/month in egress fees, alongside memory thrashing at the write path. Infrastructure cost scaled faster than the revenue the telemetry supported.
Executive Summary
This case study details the engineering journey of architecting a bespoke telemetry engine capable of sustaining 1,000,000 Requests Per Second (RPS) with a 32 KB payload per request (resulting in a continuous ingestion rate of 32 GB/s, or approximately 84 Petabytes (PB) of data per month). The architecture was required to deliver real-time 1:1 live reads, query capabilities for historical data by time range, and strict structural resilience, all while staying within a highly constrained operational expenditure (OpEx) ceiling of $175,000 monthly.
Traditional cloud-native designs and off-the-shelf database systems introduce catastrophic write amplification, excessive memory footprint, and massive egress overhead. By transitioning the infrastructure to Oracle Cloud Infrastructure (OCI), isolating compute and storage via cell-based configurations, and developing a custom, zero-allocation, memory-mapped (mmap) ring buffer engine in Go, we eliminated database compaction bottlenecks and network egress tax. This system achieved deterministic scale and static hardware utilization, driving monthly infrastructure expenditures below the target threshold.
1. The Core Mandate & Scale Economics
Operating a telemetry system for fully autonomous robots at a scale of 1,000,000 RPS introduces harsh physical constraints. Below is the baseline requirement and design math:
1.1 Sizing Calculations
To calculate the raw network throughput (in Gbps) required to ingest traffic given requests , payload size (in KB), packet and protocol overhead , and target hardware utilization :
For our mandate:
- Payload Size (): .
- Ingestion Volume: .
- Sustained Throughput: ( raw network pipe).
- Monthly Storage Volume: .
- Overhead (): (due to protocol encapsulation over gRPC/TCP).
- Target Infrastructure Utilization (): (to prevent queuing backpressure).
Using these inputs, the required global network capacity to sustain ingestion is:
At this velocity, standard database layers collapse. The system requires concurrent read/write access:
- Live Read Path: Real-time 1:1 tapping of the telemetry stream for active dashboard monitoring.
- Historical Query Path: Index-driven access by arbitrary timestamp ranges to verify robotic state histories.
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef crimson fill:#2a1111,stroke:#ff4444,stroke-width:1px,color:#ff8888,text-align:left
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
Goal["<b>MAIN REQUIREMENT</b><br>1,000,000 RPS Sustained | 32KB Payload"]:::prominent
Math["<b>DESIGN MATH</b><br>32 Gigabytes per second (GB/s)<br>~84 Petabytes per month"]:::prominent
Reads["<b>READ CAPABILITIES</b><br>1. Real-time 1:1 Live Read<br>2. Historical Data Access by Time Range"]:::prominent
Goal ~~~ Math ~~~ Reads
2. Baseline Architecture & Systemic Failures
The industry standard approach to high-throughput ingestion relies on a relational engine backstopped by a fast caching layer. We analyzed and tested this baseline to verify its limits.
2.1 The PostgreSQL & Redis Buffer Collapse
In this traditional design, clients write to an API layer that puts data directly into an in-memory Redis cache cluster acting as a buffer. Background workers then poll Redis, bundle payloads, and write them sequentially to a persistent relational store (PostgreSQL).
flowchart LR
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
Clients(("Client Applications")):::steel
%% Critical Path at the Top
subgraph HotPath ["Critical Path: Real-Time Ingestion"]
direction LR
NLB["Network Load Balancer"]:::gold
App["Application Server"]:::prominent
Redis[("Redis Cluster<br/>(High-Throughput Write Buffer)")]:::crimson
end
%% Background Path Below
subgraph Background ["Asynchronous Persistence Tier"]
direction LR
Worker(("Batch Processor")):::ghost
DB[("PostgreSQL<br/>(System of Record)")]:::sage
end
%% Flow connections
Clients -- "Tx: Ingress Requests" --> NLB
NLB -- "Rx: Egress Responses" --> Clients
NLB -- "Tx: Routed Traffic" --> App
App -- "Rx: Acknowledgements" --> NLB
App -- "Tx: Low-Latency Memory Writes" --> Redis
%% Background connections
Redis -. "Rx: Asynchronous Polling" .-> Worker
Worker -- "Tx: Bulk Persistence Operations" --> DB
Why it fails under load:
- Database Write Degradation: PostgreSQL forces the operating system to organize data pages on disk via locks and B-Trees. Under high-velocity writes, lock contention spikes, degrading disk write throughput to a fraction of the baseline.
- Drain Rate Discrepancy: The write velocity of the background workers into PostgreSQL is bounded by disk I/O, which is capped at ~50,000 IOPS on high-performance drives. Since ingestion writes occur at 1,000,000 RPS, the drain rate is slower than the ingestion rate.
- Buffer Saturated in 30 Seconds: At 32 GB/s, a 30-node Redis cluster with 1 TB of total RAM is filled to capacity in less than 32 seconds (). Once the memory buffer saturates, the API layer blocks incoming socket connections, causing immediate timeouts, packet drops, and catastrophic data loss.
- Runtime and Memory Overhead: Utilizing large nodes running NodeJS with PM2 or Python workers introduces massive garbage collection (GC) and Inter-Process Communication (IPC) overhead, consuming resources simply to maintain socket states.
2.2 The Hyperscaler Managed Services Cost Trap
To scale past local database bottlenecks, we evaluated cloud-native managed services on Amazon Web Services (AWS) using Auto-Scaling Groups, Amazon Managed Streaming for Apache Kafka (MSK), ElastiCache (Redis), and Amazon S3.
graph TD
%% ── Classes ─────────────────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
%% 1. Input Source
Users(["Clients"]):::prominent
%% 2. Entry Point
Users -->|Incoming Requests| LB["Load Balancer"]:::steel
%% Region Boundary
subgraph Region["Cloud Region"]
direction TB
%% Availability Zone 1
subgraph AZ1["Availability Zone 1"]
direction TB
Compute_AZ1["Compute Instances"]:::steel
MQ_AZ1["Message Queue"]:::sage
Cache_AZ1["Distributed Cache"]:::crimson
Compute_AZ1 -->|Write Events| MQ_AZ1
Compute_AZ1 -->|Read/Write| Cache_AZ1
end
%% Availability Zone 2
subgraph AZ2["Availability Zone 2"]
direction TB
Compute_AZ2["Compute Instances"]:::steel
MQ_AZ2["Message Queue"]:::sage
Cache_AZ2["Distributed Cache"]:::crimson
Compute_AZ2 -->|Write Events| MQ_AZ2
Compute_AZ2 -->|Read/Write| Cache_AZ2
end
%% 4. Data Layer Synchronization
MQ_AZ1 -.->|Sync| MQ_AZ2
Cache_AZ1 -.->|Sync| Cache_AZ2
end
%% 3. Scaling Mechanics (Moved outside Region for layout)
subgraph Scaling["Auto-Scaling"]
direction LR
HPA["Horizontal Scaling"]:::ghost
CA["Node Scaling"]:::ghost
end
LB -->|Distributes Traffic| Compute_AZ1
LB -->|Distributes Traffic| Compute_AZ2
%% Scaling Interactions
Scaling -.->|Monitors and Scales| Compute_AZ1
Scaling -.->|Monitors and Scales| Compute_AZ2
While cloud-native managed services resolve write limits through automatic scaling, the utility cost at this ingest rate is the constraint:
graph TD
%% ── Classes ─────────────────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
%% ── Main Header ─────────────────────────────────────────
TotalCost(["Monthly Baseline: ~$8,642,000"]):::prominent
%% ── List Layout Using Subgraphs & Links ─────────────────
subgraph Network ["1. Network ($5.76M)"]
direction TB
Egress["Internet Egress (84 PB @ $0.05/GB)<br/>$4,200,000"]:::crimson
InterAZ["Inter-AZ Transfer (66% @ $0.02/GB)<br/>$1,120,000"]:::crimson
OtherNetwork["..."]:::ghost
Egress --- InterAZ --- OtherNetwork
end
subgraph Compute ["2. Load Balancing & Compute ($990k)"]
direction TB
LB["Load Balancer (~32k LCU)<br/>$140,000"]:::steel
OtherCompute["..."]:::ghost
LB --- OtherCompute
end
subgraph Storage ["3. Storage ($1.9M+)"]
direction TB
S3M1["Object Storage Month 1 (84 PB @ $0.021/GB)<br/>$1,764,000"]:::crimson
S3M23["Object Storage Month 2 (168 PB): $3,528,000<br/>Object Storage Month 3 (252 PB): $5,292,000"]:::crimson
OtherStorage["..."]:::ghost
S3M1 --- S3M23 --- OtherStorage
end
subgraph Traps ["4. Fatal Cost Traps"]
direction TB
NAT["Ingress / NAT Gateway Fee (84 PB)<br/>+$3,780,000 / mo"]:::ghost
S3Unbatched["Unbatched Storage Puts (2.6T Requests)<br/>+$12,900,000 / mo"]:::ghost
LogAll["Unsampled Logging<br/>Unlimited Hidden Cost"]:::ghost
NAT --- S3Unbatched --- LogAll
end
%% Connections from Total
TotalCost --> Network
TotalCost --> Compute
TotalCost --> Storage
TotalCost --> Traps
- Egress Fees: To serve the live dashboard reads, approximately 84 PB of data must transit the cloud boundary. On AWS, egress rates of generate a monthly network bill of $4,200,000.
- Inter-Availability Zone (AZ) Taxes: Replicating data across AZs for high availability costs (billed in both directions) for inter-AZ data transfer. Assuming 66% of the 32 GB/s traffic traverses AZ boundaries, this adds $1,120,000 monthly.
- Storage Ingestion Fees (PUT APIs): Sending unbatched 32 KB telemetry payloads to S3 generates 2.59 trillion API calls per month. At per 1,000 PUT requests, this incurs an additional $12,950,000 monthly storage transaction fee.
- Compounding Storage Baseline: Standard S3 storage costs . Storing 84 PB in Month 1 costs $1,764,000, which compounds to $3,528,000 in Month 2, and $5,292,000 in Month 3.
3. The Architectural Iterations & Progression
To navigate these limits, we executed four distinct architectural iterations, refining the physical and financial performance at each stage.
3.1 Iteration 1: Cloud-Native Managed Services (AWS Optimization)
We attempted to optimize the AWS topology by reducing the payload size. However, we realized that the 32 KB payload was already a pre-compressed telemetry block (e.g., packed binary format or compressed JSON), meaning further compression was physically impossible. We had to ingest and persist the full 32 KB payload at 1,000,000 RPS, keeping the network demand at a relentless 256 Gbps (32 GB/s) baseline. We utilized Route 53 with latency-based routing to 10x Network Load Balancers and ran local Redis caches synced eventually to ScyllaDB on AWS EC2 nodes.
- Result: The inability to compress the payload meant network requirements remained at 256 Gbps. Coupled with NAT gateway processing fees ($0.045 per GB) and inter-AZ network charges, the monthly OpEx baseline stayed over $1,200,000, rendering this optimization attempt a failure.
3.2 Iteration 2: Kernel-Bypassed Seastar & OCI Hybrid Stack
To eliminate AWS’s high network fees, we moved the entire infrastructure to Oracle Cloud Infrastructure (OCI), which offers free inbound traffic, low egress rates, and unmetered internal VCN transit.
To bypass kernel context switches, we implemented a C++ Seastar-based stack: a Golang API fleet writing concurrently to a Redpanda queue broker (built on the Seastar thread-per-core framework) for fast, append-only logs, and to a Dragonfly cache cluster for high-velocity reads. A background worker fleet drained Redpanda into a ScyllaDB ring deployed on local NVMe drives.
graph TD
classDef global fill:#1a365d,stroke:#2b6cb0,stroke-width:2px,color:#fff;
classDef compute fill:#2d3748,stroke:#4a5568,stroke-width:2px,color:#fff;
classDef fast fill:#d69e2e,stroke:#b7791f,stroke-width:2px,color:#fff;
classDef slow fill:#2c7a7b,stroke:#38b2ac,stroke-width:2px,color:#fff;
Client((Global Users))
subgraph The_Edge_Layer [Edge Layer]
CF_DNS[Cloudflare DNS \n Traffic Routing & DDoS Protection]:::global
CF_CDN[Cloudflare CDN \n Static Cache & Edge Routing]:::global
end
subgraph LB_Layer [Load Balancing]
HAProxy[OCI NLB \n Network Load Balancer]:::fast
end
subgraph VM_BareMetal_Infrastructure [Cloud Infrastructure]
subgraph Compute_Layer [Compute Fleet]
API[Golang API Fleet \n Fiber on ARM]:::compute
end
subgraph Fast_Path [The Fast Path - Milliseconds]
Dragonfly[(Dragonfly Cluster \n Multi-threaded Cache)]:::fast
Redpanda[Redpanda Brokers \n Append-Only Write Log]:::fast
end
subgraph Async_Slow_Path [The Async/Slow Path]
Worker[Go Background Workers \n Batch Processing]:::compute
Scylla[(ScyllaDB Ring \n Permanent Storage)]:::slow
S3[(OCI Object Storage / S3 \n Cold Data Archive)]:::slow
end
end
Client -->|1- DNS Request| CF_DNS
CF_DNS -.->|2- Resolved LB IP| Client
Client ==>|3- HTTP Request| CF_CDN
CF_CDN ==>|4- Cache Miss / Route to Origin| HAProxy
HAProxy ==>|5- L4 TCP Connection| API
API ==>|6a- Append Log| Redpanda
API ==>|6b- Cache Recent Write| Dragonfly
API -.->|6c- Fetch Recent Data| Dragonfly
Redpanda ==>|7- Batch Consume| Worker
Worker ==>|8a- Bulk Insert| Scylla
Worker -.->|8b- Evict Temp Key| Dragonfly
Worker -.->|8c- Soft Purge Surrogate Tag| CF_CDN
API -.->|9- Fetch Hot Data| Scylla
API -.->|9a- Go Singleflight Coalescing| API
API -.->|9b- Write Frequent History - Hot Data - to Cache| Dragonfly
Worker -.->|10a- Fetch Oldest/Least Read Data| Scylla
Worker -.->|10b- Offload & Archive| S3
The failure modes:
- Raft Consensus Multiplier: Redpanda requires a Raft consensus quorum. To guarantee high availability, replication factor (RF) must be set to at least 3. This tripled the required node count and disk capacity, driving compute costs beyond our budget.
- Local NVMe Storage Limit: ScyllaDB was bound to local NVMe drives. When a node reached its storage limit, the cluster required scaling.
- Data Loss Risk: Because data sat on local NVMe, if a node crashed, its unreplicated data block was lost, exposing the system to data loss.
- Network Bandwidth Saturation: Servicing concurrent writes, cache updates, and background consumer drains pushed the VMs' Virtual NICs (VNICs) to their limit, causing packet loss.
3.3 Iteration 3: Bare ScyllaDB & Network Disk Compaction Bottleneck
To simplify the topology, we removed Redpanda and Dragonfly, routing the Golang API fleet directly to a ScyllaDB cluster. To prevent data loss from node failures, we moved ScyllaDB from local NVMe to OCI Elastic Network Block Volumes, enabling automated snapshot backups.
graph TD
%% Define Classes
classDef global fill:#1a365d,stroke:#2b6cb0,stroke-width:2px,color:#fff;
classDef compute fill:#2d3748,stroke:#4a5568,stroke-width:2px,color:#fff;
classDef storage fill:#2c7a7b,stroke:#38b2ac,stroke-width:2px,color:#fff;
%% New High-Contrast class for Crucial Functionality & Testing
classDef crucial fill:#e53e3e,stroke:#c53030,stroke-width:4px,color:#fff,stroke-dasharray: 5 5;
Client((Global Users))
subgraph The_Edge_Layer [Edge Layer - Optional for Core Path]
CF_DNS[Cloudflare DNS \n Traffic Routing]:::global
CF_CDN[Cloudflare CDN \n Edge Security]:::global
end
%% CRUCIAL: High-throughput entry point must be tested
subgraph LB_Layer [LB Layer]
NLB[OCI NLB \n L4 Stateless Balancing]:::crucial
end
subgraph Cloud_Infrastructure [OCI Cell Infrastructure - 1 of 8]
%% CRUCIAL: API logic and Shard-Awareness is critical for performance
subgraph Compute_Layer [API Fleet]
API[Golang API Fleet \n 5x A1.Flex Nodes]:::crucial
end
%% CRUCIAL DB / Optional S3
subgraph Storage_Layer [Unified Data Layer]
Scylla[(ScyllaDB Cluster \n 1.5TB Block Volumes / 120 VPU)]:::crucial
ObjStorage[(OCI Object Storage \n Tiered Storage / Archive)]:::storage
end
end
Client -->|1| CF_DNS
CF_DNS -.->|2| Client
Client ==>|3| CF_CDN
CF_CDN ==>|4| NLB
NLB ==>|5| API
%% CRUCIAL: High-load data path
API ==>|6 - Critical Write/Read| Scylla
Scylla -.->|7| API
Scylla -.->|8 - Tiering| ObjStorage
The failure modes:
- LSM Tree Write Amplification: ScyllaDB utilizes a Log-Structured Merge (LSM) tree. This architecture writes to a Memtable, flushes to SSTables on disk, and runs compaction cycles. Compaction cycles multiply the raw write throughput by a Write Amplification Factor (WAF) of 4.
- Commit Log Contention: In addition to SSTables, ScyllaDB writes each incoming payload to a Commit Log on disk, adding of overhead.
- Disk Performance Bottleneck: To support a WAF of 4 () and the Commit Log (), the network disks required a sustained throughput of . Pushing this volume of I/O over network blocks saturated OCI's network interface limits. This caused write queuing, latency spikes, and system failure, proving that LSM-based engines cannot be run directly over network block volumes at this scale.
3.4 Iteration 4: Aerospike Hybrid Storage & Apache Pulsar/Bookkeeper
We replaced ScyllaDB with Aerospike DB operating in hybrid mode (indexes in RAM, payloads on raw SSDs). To handle disaster recovery, we introduced Apache Pulsar with an Apache BookKeeper storage fleet. BookKeeper was configured with DbLedgerStorage (memory-mapped index) and double writes disabled (journalWriteData=false), storing data on network block volumes backed up by weekly snapshots.
To reduce Network Load Balancer (NLB) load, we implemented a Smart Client Routing connection flow.
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
%% ── Subgraph Styles ───────────────────────────────────
style Compute_Fleet fill:#181922,stroke:#8896a8,stroke-width:1.5px,stroke-dasharray:5 5
style Specs_Compute fill:none,stroke:none
style BK_Fleet fill:#1d1616,stroke:#a87878,stroke-width:1.5px,stroke-dasharray:5 5
style Specs_BK fill:none,stroke:none
style DB_Fleet fill:#161d17,stroke:#7a9e7e,stroke-width:1.5px,stroke-dasharray:5 5
style Specs_DB fill:none,stroke:none
NLB[OCI NLB]:::gold
subgraph Compute_Fleet [Compute Fleet]
subgraph Specs_Compute [Compute Specifications]
Info_Compute["Total Nodes: 20<br>Shape: VM.Standard.A1.Flex (40 OCPU)<br>Workload: Go API + Apache Pulsar Brokers<br>Network: 800 Gbps Capacity"]:::prominent
end
VM1[Compute Node 1]:::steel
VM2[Compute Node 2]:::steel
VMDots[...]:::ghost
VM20[Compute Node 20]:::steel
end
subgraph BK_Fleet [Apache BookKeeper Fleet]
subgraph Specs_BK [BookKeeper Specifications]
Info_BK["Total Nodes: 36<br>Shape: VM.Standard.A1.Flex (40 OCPU)<br>Config: E=2, WQ=2, AQ=1 (WAF 1, RF 2)"]:::prominent
end
BK1[Bookie Node 1]:::crimson
BK2[Bookie Node 2]:::crimson
BKDots[...]:::ghost
BK36[Bookie Node 36]:::crimson
end
subgraph Storage_Fleet [Block Storage Fleet]
subgraph Specs_Storage [Storage Specifications]
Info_Storage["Standard Block Volumes<br>Base 36, Scales to 112 disks max<br>Backups: Weekly Snapshots"]:::prominent
end
Vol1[(Block Volume 1)]:::ghost
Vol2[(Block Volume 2)]:::ghost
end
BK1 --- Vol1
BK2 --- Vol2
subgraph DB_Fleet [Aerospike Database Fleet]
subgraph Specs_DB [DB Specifications]
Info_DB["Total Nodes: 12<br>Shape: VM.DenseIO.E4.Flex<br>Configuration: RF 1 (per cell), Hybrid Mode"]:::prominent
end
DB1[Aerospike Node 1]:::sage
DB2[Aerospike Node 2]:::sage
DBDots[...]:::ghost
DB12[Aerospike Node 12]:::sage
end
NLB -- "256 Gbps" --> VM1
NLB --> VM2
NLB -.-> VMDots
NLB --> VM20
Compute_Fleet -- "256 Gbps<br>Dual Write (Backup & Recovery)" --> BK_Fleet
Compute_Fleet -- "256 Gbps<br>Dual Write (Main DB)" --> DB_Fleet
Smart Client Connection Sequence:
- Discovery Phase: The application client queries the OCI NLB on port 3000 as a seed node.
- Topology Discovery: The seed node returns a partition mapping containing the real private IPs of all Aerospike cluster nodes.
- Bypass NLB: The client establishes direct TCP connections to each Aerospike node IP. The NLB path is abandoned, directing subsequent data traffic straight to the target nodes.
sequenceDiagram
autonumber
participant Client App as Application (Smart Client)
box "OCI Network Infrastructure" #fee
participant NLB as OCI NLB L4 (Discovery Only)
end
box "Aerospike Cluster (Subnet B)" #e1f5fe
participant NodeA as Aerospike Node A
participant NodeB as Aerospike Node B (Owner of 'X')
end
Note over Client App, NodeA: PHASE 1: DISCOVERY (Low Bandwidth)
Note right of Client App: App Startup:<br/>Points to NLB IP as 'Seed'
Client App->>NLB: [SEED REQ] Where is the cluster?
activate NLB
NLB->>NodeA: Forward to one node
deactivate NLB
activate NodeA
Note right of NodeA: node.conf:<br/>advertises REAL Private IPs<br/>(access-address)
NodeA-->>NLB: Returns Partition Map & Node IPs
activate NLB
NLB-->>Client App: Returns Partition Map & Node IPs
deactivate NLB
deactivate NodeA
Note over Client App: Smart Client opens DIRECT TCP connections<br/>to every Node IP. The NLB path is now abandoned.
Note over Client App, NodeB: PHASE 2: HYPERSCALE DATA FLOW (32 GB/s)
Note right of Client App: Req Record 'X'.<br/>Smart Map says "Node B owns 'X'"
Client App->>NodeB: [DIRECT REQ] Send me Record 'X'
activate NodeB
NodeB-->>Client App: Return Record 'X'
deactivate NodeB
Note over NLB: NLB is IDLE.<br/>32 GB/s traffic flows directly<br/>over individual node NICs.
To limit network utilization, we configured BookKeeper’s skipListSizeLimit to 2 GB. This aggregated incoming 32 KB payloads in RAM and wrote them to disk sequentially in large chunks.
To reduce data egress charges, we routed historical queries to a flat-rate OCI FastConnect port ( connection linked to collocated Arista routers), bypassing standard egress fees.
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
classDef rejected fill:#2a1111,stroke:#ff4444,stroke-width:2px,color:#ff8888,stroke-dasharray:5 5
%% ── Subgraph Styles ───────────────────────────────────
style Compute_Fleet fill:#181922,stroke:#8896a8,stroke-width:1.5px,stroke-dasharray:5 5
style Specs_Compute fill:none,stroke:none
style DB_Fleet fill:#161d17,stroke:#7a9e7e,stroke-width:1.5px,stroke-dasharray:5 5
style Specs_DB fill:none,stroke:none
style XDR_Storage fill:#1d1616,stroke:#ff4444,stroke-width:2px,stroke-dasharray:10 5
style Specs_XDR fill:none,stroke:none
NLB[OCI NLB]:::gold
subgraph Compute_Fleet [Compute Fleet]
subgraph Specs_Compute [Compute Specifications]
Info_Compute["Total Nodes: 20<br>Shape: VM.Standard.A1.Flex (40 OCPU)<br>Workload: Go API<br>Network: 800 Gbps Capacity"]:::prominent
end
VM1[Compute Node 1]:::steel
VM2[Compute Node 2]:::steel
VMDots[...]:::ghost
VM20[Compute Node 20]:::steel
end
subgraph DB_Fleet [Aerospike Database Fleet]
subgraph Specs_DB [DB Specifications]
Info_DB["Total Nodes: 12<br>Shape: VM.DenseIO.E4.Flex<br>Configuration: RF 2, Hybrid Mode"]:::prominent
end
DB1[Aerospike Node 1]:::sage
DB2[Aerospike Node 2]:::sage
DBDots[...]:::ghost
DB12[Aerospike Node 12]:::sage
end
subgraph XDR_Storage ["XDR Recovery / Backup Storage (Rejected)"]
subgraph Specs_XDR [XDR Specifications]
Info_XDR["OCI Object Storage / Network Volume<br>Requires extra 256 Gbps reserved pipe<br>High Bandwidth Consumption & Latency"]:::rejected
end
OS1[(Object Storage / Vol)]:::rejected
end
NLB -- "256 Gbps" --> VM1
NLB --> VM2
NLB -.-> VMDots
NLB --> VM20
Compute_Fleet -- "256 Gbps<br>Write (Main DB)" --> DB_Fleet
DB_Fleet == "XDR Sync<br>⚠️ Extra 256 Gbps Pipe Required" === XDR_Storage
linkStyle 5 stroke:#ff4444,stroke-width:3px,color:#ff8888,stroke-dasharray:5 5
The configuration specifications:
1. aerospike.conf Block Engine Profile
# Aerospike Community Edition Configuration
service {
user root
group root
pidfile /var/run/aerospike/asd.pid
paxos-single-replica-limit 1 # Single replica mapping (RF=1) per cell
service-threads 80 # 2x OCPU allocation for core pinning
transaction-queues 80
transaction-threads-per-queue 4
proto-fd-max 200000
}
namespace test {
replication-factor 1
memory-size 60G # DRAM allocated for hot indexes
default-ttl 0 # Never expire writes
# Direct NVMe interface bypasses OS Page Cache
storage-engine device {
device /dev/sdb
device /dev/sdc
device /dev/sdd
device /dev/sde
device /dev/sdf
device /dev/sdg
device /dev/sdh
device /dev/sdi # 8x iSCSI volumes
write-block-size 1048576 # 1 MB blocks to optimize disk writes
read-page-cache false
post-write-queue 256
defrag-lwm-pct 50 # Defrag blocks at <50% occupancy
defrag-sleep 100 # Wait 100us between defrag cycles
max-write-cache 128M
}
}
2. bookkeeper.conf Ingestion Settings
# Apache BookKeeper Settings for Ingestion
ledgerStorageClass=org.apache.bookkeeper.bookie.storage.ldb.DbLedgerStorage
journalWriteData=false
skipListSizeLimit=2147483648
diskUsageThreshold=0.95
The failure modes:
- Licensing Costs: Aerospike Enterprise licensing costs scale with storage volume. At a data volume of 84 PB per month, the licensing fees exceeded our budget limits.
- Cell Boundaries limits: While cell-based clusters can isolate storage nodes to stay within community licensing bounds, managing multi-datacenter data consistency added significant operational overhead.
- Write Failures during Network Slowdowns: If OCI network transit slowed down, Aerospike’s memory buffers filled up and rejected write operations, causing data loss.
4. The Final Architecture: State Machine Ring Buffer & Custom Storage Engine
To meet both physical and budget requirements, we designed a custom telemetry engine that replaces third-party database systems. The core design shifts data persistence from off-the-shelf databases to a custom, memory-mapped write-ahead log (WAL) that offloads data to OCI Object Storage.
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
subgraph OCI ["Oracle Cloud Infrastructure"]
subgraph Core ["Core Ingestion Architecture"]
NLB["Network Load Balancer (Layer 4)"]:::prominent
VMPool["Compute Pool<br>(40 OCPU / 128GB RAM VMs)<br>Distributed across Fault Domains"]:::steel
NetDisks[("Elastic Network Disks<br>(Buffer & WAL)")]:::gold
end
subgraph StorageTier ["Data & Analytics Tier"]
ObjStore[("OCI Object Storage<br>(Persistent Archive)")]:::sage
Trino["OCI Big Data Service<br>(Trino / Historical Query)"]:::gold
end
end
NLB -- "1M RPS" --> VMPool
VMPool -- "Appends to" --> NetDisks
NetDisks -- "Offloads Frozen Data" --> ObjStore
ObjStore -- "Historical Analytics" --> Trino
class OCI ghost
4.1 Cell-Based Architecture
To stay within OCI network limits and manage risk, we split the system into 4 isolated cells.
- Cell Capacity: Each cell is configured to handle 250,000 RPS (65 Gbps, 8 GB/s ingestion throughput).
- Isolation Policy: Cells share no network pathing, load balancers, or metadata synchronization, preventing cascade failures.
- Universal Scalability Law (USL) Optimization: The cell-based design keeps our node count within the linear scaling range of the USL curve. This prevents the performance degradation that occurs when large clusters spend more CPU time coordinating states than processing data.
4.2 Stateless Compute & Storage Layout
Each cell contains a stateless compute fleet and an elastic storage tier.
Compute Nodes (12x per Cell, 48x globally):
- Shape:
VM.Standard.A1.Flex(40 Ampere Altra ARM Cores, 128 GB RAM, 50 GB Boot Volume). - Network Capacity: OCI allocates network throughput based on CPU core count. A 40 OCPU instance receives 40 Gbps (5,000 MB/s) of full-duplex network bandwidth.
- Base Utilization Target: 53.33% ( of network capacity consumed per node during normal operation).
Hardware Resiliency Justification:
The compute nodes are distributed evenly across 3 OCI Fault Domains (FD) (4 VMs per FD).
- Fault Tolerance: If a fault domain goes offline, we lose 4 VMs. The remaining 8 VMs must pick up the cell load of 250,000 RPS.
- Node Load Margin: With 8 VMs running, the utilization per node rises to:
This stays within the safe 80% operating limit, preventing system crashes. If we configured the cell with only 9 VMs (running at 71.1% base utilization), a fault domain failure (losing 3 VMs) would push the remaining 6 VMs to:
This exceeds VM capacity, causing immediate node crashes and cascade failure.
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
classDef highlight fill:#2d2417,stroke:#c8a96e,stroke-width:1px,color:#e8d5a8
subgraph InfraCore ["Infrastructure Engineering"]
NLB["Network Load Balancer (Layer 4)"]:::prominent
subgraph ComputeGrid ["Compute Pool: 12x VMs (40 OCPU, 128GB RAM, 53% Base Util)"]
direction LR
subgraph FD1 ["Fault Domain 1"]
VM1["VM 1<br>40 OCPU<br>128GB RAM<br>50GB Boot Volume"]:::highlight
VM2["VM 2"]:::steel
VM3["VM 3"]:::steel
VM4["VM 4"]:::steel
end
subgraph FD2 ["Fault Domain 2"]
VM5["VM 5"]:::steel
VM6["VM 6"]:::steel
VM7["VM 7"]:::steel
VM8["VM 8"]:::steel
end
subgraph FD3 ["Fault Domain 3"]
VM9["VM 9"]:::steel
VM10["VM 10"]:::steel
VM11["VM 11"]:::steel
VM12["VM 12"]:::steel
end
end
subgraph DiskGrid ["VM 1 Network Disks: 8x Block Volumes (1525GB, 120 VPU)"]
direction LR
D1[("D1 Active<br>1525GB<br>120 VPU<br>2.68GB/s")]:::gold
D2[("D2<br>Next")]:::steel
D3[("D3<br>Next")]:::steel
D4[("D4<br>Backup")]:::steel
D5[("D5<br>Clean")]:::steel
D6[("D6<br>Clean")]:::steel
D7[("D7<br>Clean")]:::steel
D8[("D8<br>Clean")]:::steel
end
DR["DR Rationale: 1 FD loss leaves 8 VMs at ~80% util.<br>9 VMs would spike to ~107% util (Cascade Crash)."]:::sage
end
NLB --> ComputeGrid
VM1 -. "Attached Volumes" .-> DiskGrid
ComputeGrid -. "Capacity Rules" .-> DR
class InfraCore,ComputeGrid,FD1,FD2,FD3,DiskGrid ghost
Storage Disks:
Each VM is attached to 8x Elastic Network Block Volumes via iSCSI (multipathing enabled).
- Disk Size: 1525 GB (1.5 TB) per disk.
- Performance Tier: 120 VPUs per GB (Ultra High Performance).
- Throughput Sweet Spot: OCI block volumes require a capacity of 1.5 TB to output their maximum performance limit of 350 MB/s of disk throughput.
4.3 Software Implementation Details
The Go telemetry application bypasses traditional file-writing functions and database protocols.
flowchart TB
%% Compute Layer Golang Application Logic Diagram
subgraph External_Ingress ["External Ingress"]
NLB["OCI L4 NLB<br>(65 Gbps / 250k RPS)"]
end
subgraph Go_Node ["Golang Compute Node (Zero-Allocation Engine)"]
subgraph Gnet_Ingestion ["gnet TCP Server"]
MainReactor["gnet Main Reactor<br>(Accepts Connections)"]
SubReactors["gnet Sub-Reactors<br>(1 per CPU core)"]
Codec["Length-Prefix Codec<br>(4B Length + 32KB Payload)"]
MainReactor -->|Distributes| SubReactors
SubReactors -->|Stream| Codec
end
subgraph Memory_Management ["Memory Management"]
SyncPool[("sync.Pool<br>(32KB Byte Arrays)")]
Codec <-->|Borrow / Return| SyncPool
end
subgraph Write_Pipeline ["Write Engine (Zero-Backpressure)"]
LockFreeAppend["Lock-Free Append<br>(atomic.AddInt64)"]
Mmap["syscall.Mmap WAL<br>(100GB Chunks in RAM)"]
Codec -->|Payload| LockFreeAppend
LockFreeAppend -->|"copy()"| Mmap
end
subgraph Live_Read ["Live Tap (On-Demand)"]
LiveSwitch{"isLiveClientActive?"}
LiveChan["liveStreamChan<br>(Non-Blocking Broadcast)"]
LiveClient["Live Client<br>(gRPC / WS)"]
LockFreeAppend --> LiveSwitch
LiveSwitch -->|True| LiveChan
LiveChan -->|Zero I/O Cost| LiveClient
end
subgraph Archival_Offloader ["Background Offloader"]
SealedChunk["Sealed 100GB Chunk"]
UploadGoroutine["OCI Go SDK UploadManager"]
S3[("OCI Object Storage<br>(Long-Term Archive)")]
ResetChunk["madvise(MADV_DONTNEED)<br>Truncate & Reuse"]
Mmap -->|Hits 100GB Boundary| SealedChunk
SealedChunk --> UploadGoroutine
UploadGoroutine -->|Stream| S3
UploadGoroutine -->|200 OK| ResetChunk
ResetChunk -.-> Mmap
end
subgraph Historical_Reads ["Historical Read Router"]
Gateway["Query Aggregator / API Gateway"]
TimeIndex["In-Memory TimeIndex<br>(B-Tree)"]
Gateway -->|"Query (Timestamp)"| TimeIndex
TimeIndex -->|Recent Data| Mmap
TimeIndex -->|"Old Data (404)"| Gateway
Gateway -.->|Redirect| Trino["OCI Big Data / Trino"]
Trino -.->|Fetch| S3
end
end
subgraph Hardware_Storage ["Hardware Layer"]
OS_PageCache["Linux Kernel Page Cache<br>(msync / fdatasync)"]
BlockVolumes[("4x OCI Block Volumes<br>(Ring Buffer Architecture)")]
Mmap <-->|Asynchronous Flush| OS_PageCache
OS_PageCache <--> BlockVolumes
end
%% Connections
NLB -->|Raw TCP| MainReactor
%% Styling
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
class NLB,LiveClient,S3,Gateway,Trino steel;
class SyncPool,Mmap,TimeIndex sage;
class BlockVolumes prominent;
class MainReactor,SubReactors,Codec,LockFreeAppend,UploadGoroutine gold;
class OS_PageCache ghost;
1. Ingestion Layer (gnet)
- We use the
gnetlibrary (an event-loop networking framework) in raw TCP mode instead of HTTP. - Multi-Reactor Setup: The Main Reactor intercepts incoming connections and hands them off to Sub-Reactors. We pin one Sub-Reactor to each CPU core, preventing context switches.
- Protocol Framing: We use a length-prefix format:
[4-byte Length Integer] [32 KB Payload]. The framework buffers data until a complete 32,772-byte payload is assembled before triggering processing.
2. Zero-Allocation Memory Engine
- sync.Pool: Slices are managed via
sync.Poolto avoid memory allocation churn. - Memory-Mapped File (mmap): The Go app maps the active block volume directly into userspace memory via
syscall.Mmap. Payloads are appended directly to this memory array. - Lock-Free pointer reservation: Multiple request threads write to the mapped memory concurrently without locking. When a payload arrives, the thread atomically reserves 32,780 bytes (32,768-byte payload + 12-byte WAL record header containing an 8-byte nanosecond timestamp and a 4-byte CRC32 checksum):
offset := atomic.AddInt64(&RingBuffer.Offset, 32780)
This reserves a slice in the mmap buffer. The thread copies the payload into its reserved space using Go's built-in copy() function.
- Kernel Flushes: To prevent page cache saturation, the application periodically issues
syscall.Msync/fdatasynccalls, flushing data to disk in controlled, sequential blocks.
4.4 Ingestion & Storage Lifecycle
The memory-mapped Write-Ahead Log (WAL) operates as a state machine rotating across the attached network block volumes.
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
App["App Logic<br>(State Machine & Monitor)"]:::steel
ObjStore[("OCI Object Storage")]:::sage
subgraph Disks ["Elastic Network Disks (8x Total per Node: Active, Next, Backup)"]
DiskA["Disk Set A<br>(Active Append)"]:::gold
DiskB["Disk Set B<br>(Frozen / Next)"]:::steel
DiskC["Disk Set C<br>(Backup Buffer)"]:::steel
DiskE["Emergency Disks<br>(Provisioned On-Demand)"]:::crimson
end
%% Normal Lifecycle
DiskA -- "1. Fills to 95% -> Pivot" --> DiskB
DiskB -- "2a. Offload Success" --> ObjStore
ObjStore -. "Clear Disks & Reuse" .-> DiskA
%% Blocked Lifecycle
DiskB -- "2b. Offload Delayed & Fills -> Pivot" --> DiskC
DiskC -- "3. Active hits 60% & Offload Blocked -> Pivot" --> DiskE
%% Application Intervention
App -. "Provisions & Mounts" .-> DiskE
App -. "Terminates Post-Recovery" .-> DiskE
1. Ingestion:
Telemetry data is appended to the active memory-mapped block volume (Disk A).
2. The Live Read Bypass:
When a live dashboard client connects, the Go app activates a boolean flag and opens a non-blocking Go channel. Ingestion threads write copy references directly to this channel, streaming data to live clients from RAM with zero disk read I/O.
3. Rotation State:
When Disk A reaches 95% capacity:
- The Go app updates the atomic pointer, routing new write operations to Disk B.
- Disk A is frozen. A background worker uploads the frozen 100 GB segment to OCI Object Storage using the OCI SDK
UploadManager. - Upon upload completion, the application runs
madvise(MADV_DONTNEED)to clear the RAM pages. The file is truncated, clearing the disk for reuse. - Disk C acts as a backup buffer if Object Storage upload speeds lag.
4. Dynamic Storage Provisioning:
If Object Storage uploads are delayed and active disk utilization reaches 60% with all buffer disks filled, the Go application calls the OCI API to provision and mount an emergency block volume. This prevents system crashes during object store slowdowns. Once network conditions normalize and the backlog is cleared, the emergency volumes are detached and terminated.
4.5 Historical Query Routing
To query historical data, we separate recent and cold data paths:
- Gateway Broadcast: Query requests (specifying a timestamp range) hit a Gateway Aggregator, which broadcasts the query to the nodes in the target cell.
- In-Memory B-Tree: Each Go node maintains a lightweight, in-memory B-Tree index mapping timestamps to byte offsets for the active volumes. It also tracks the
OldestLocalTimestampcurrently stored on its block volumes. - Local Read Path: If the queried range is newer than
OldestLocalTimestamp, the node locates the offsets in its local B-Tree, reads the exact byte slice from the block volume (+1 MB read), and streams it back to the Gateway. - Cold Read Path: If the range is older than
OldestLocalTimestamp, the node returns a404 Not Localresponse. The Gateway then routes the query to OCI Big Data Service (Trino), which queries the data archived in OCI Object Storage.
4.6 Single Node Load Verification
To verify performance, we analyzed VM VNIC bandwidth limits against the maximum workload:
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
classDef highlight fill:#2d2417,stroke:#c8a96e,stroke-width:1px,color:#e8d5a8
subgraph Analysis ["Peak Network Load per VM (Single Node Analysis)"]
NLB["Internet / NLB Ingress"]:::prominent
Consumer["Consumer (Live Read)"]:::sage
subgraph VM_Node ["Single VM (40 OCPU / 128GB RAM)"]
direction TB
NIC["Virtual NIC<br>(Full Duplex: 40Gbps Rx / 40Gbps Tx)"]:::highlight
Processor["Go App (Data Processor & RAM Buffer)"]:::steel
NIC <--> Processor
end
subgraph Disks ["8x Elastic Network Disks (Block Volumes)"]
direction LR
Active[("Active Disk<br>(Write Target)")]:::gold
Draining[("Draining Disk<br>(Read Source)")]:::sage
Idle[("6x Idle / Clean<br>Disks")]:::steel
end
ObjStore[("OCI Object Storage<br>(Archive)")]:::sage
%% Traffic Flows (Concurrent)
NLB -- "Inbound (Rx): Live Ingest<br>680 MB/s" --> NIC
NIC -- "Outbound (Tx): Disk Write<br>680 MB/s" --> Active
NIC -- "Outbound (Tx): Live Read (from RAM)<br>680 MB/s" --> Consumer
Draining -- "Inbound (Rx): Disk Read (Drain)<br>2,000 MB/s" --> NIC
NIC -- "Outbound (Tx): Object Storage Upload<br>2,000 MB/s" --> ObjStore
end
subgraph Justification ["Infrastructure Engineering Justification"]
direction TB
CalcRx["Receive (Rx) - Data entering the VM:<br>+ 680 MB/s: Live payload from LB<br>+ 2,000 MB/s: Read frozen disk via iSCSI<br>Total Rx: 2,680 MB/s<br>VM Limit: 5,000 MB/s (40 Gbps)<br>Headroom: 2,320 MB/s (Extremely safe margin)"]:::ghost
CalcTx["Transmit (Tx) - Data leaving the VM:<br>+ 680 MB/s: Write payload to active disk via iSCSI<br>+ 680 MB/s: Serve Live Read from RAM to consumer<br>+ 2,000 MB/s: Upload frozen data to OCI Object Storage<br>Total Tx: 3,360 MB/s<br>VM Limit: 5,000 MB/s (40 Gbps)<br>Headroom: 1,640 MB/s (Comfortable safety margin)"]:::ghost
Infra["Network Scale Justification:<br>Advertised 40Gbps VM network is full duplex (40Gbps Rx / 40Gbps Tx), giving 80Gbps total capacity.<br>This shape is mandatory to handle the concurrent 3,360 MB/s (Tx) peak load without throttling.<br>Global Scale: 4 Cells × 12 VMs = 48 VMs.<br>Storage Scale: 48 VMs × 8 Disks = 384 Network Disks."]:::gold
end
Analysis -.-> Justification
class Analysis,VM_Node,Disks,Justification ghost
-
Ingress (Rx) Load:
- Ingress Telemetry (from NLB): ().
- iSCSI Disk Read (for S3 Offload): ().
- Total Peak Rx: ().
- VM Rx Limit: ().
- Available Headroom: ().
-
Egress (Tx) Load:
- iSCSI Disk Write (Ingestion): ().
- Live Reader Stream (from RAM): ().
- Object Storage Upload: ().
- Total Peak Tx: ().
- VM Tx Limit: ().
- Available Headroom: ().
This verification proves that a VM with a 40 Gbps NIC can handle peak read and write loads concurrently.
4.7 Host OS & Kernel Tuning Script
To maintain the required 250,000 RPS per cell, the OS must be tuned via standard configuration scripts during provisioning.
#!/usr/bin/env bash
# High-Performance OS Tuning Script for Telemetry Ingestion Node
# 1. CPU & Interrupt Tuning
# Set performance CPU scaling governor
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
# Disable irqbalance to prevent cache-miss latency spikes
systemctl stop irqbalance
systemctl disable irqbalance
# Manually pin interrupts: Cores 0-7 for VNIC/iSCSI queues, Cores 8-39 for Go App threads
# (Targeted core mapping applied to local interface queues)
# 2. File Descriptors & Process Limits
cat <<EOF >> /etc/security/limits.conf
* soft nofile 1048576
* hard nofile 1048576
root soft nofile 1048576
root hard nofile 1048576
EOF
# 3. TCP & Network Stack Configuration
cat <<EOF > /etc/sysctl.d/99-telemetry-engine.conf
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 300000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.ipv4.tcp_mtu_probing = 1
net.ipv4.ip_local_port_range = 1024 65535
EOF
sysctl -p /etc/sysctl.d/99-telemetry-engine.conf
# 4. Memory & Block Device Configuration
# Disable Transparent Huge Pages (THP) to avoid memory latency overhead
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# Tune attached iSCSI volumes (sdX)
for dev in /sys/block/sd*/queue/scheduler; do
echo none > "$dev" 2>/dev/null || echo noop > "$dev" 2>/dev/null
done
for dev in /dev/sd*; do
# Increase queue requests capacity
echo 1024 > /sys/block/$(basename "$dev")/queue/nr_requests 2>/dev/null
# Disable read-ahead
blockdev --setra 0 "$dev" 2>/dev/null
done
5. Financial Ledger & ROI Verification
Below is the monthly cost breakdown for the state-machine ring buffer architecture on OCI compared against equivalent deployments on AWS.
5.1 OCI Monthly Infrastructure Cost
- Compute Instances: 48x
VM.Standard.A1.Flex(40 OCPU, 128 GB RAM):
- Boot Volumes: 48x 50 GB Boot Volumes:
- Elastic Block Volumes: 384x 1525 GB Disks (120 VPU @ $350 each):
- OCI Base Infrastructure Total: $152,907.84
- Flat-Rate Network Egress: OCI FastConnect unmetered 400 Gbps port: $20,700.00
- Total Monthly Operational Expenditure: $173,607.84
5.2 Comparative Cost Analysis (OCI vs. AWS)
| Expense Item | AWS Managed Architecture | State-Machine Ring Buffer (OCI) | Monthly Savings |
|---|---|---|---|
| Compute & Cache | $990,000 | $18,405 | $971,595 |
| Ingestion Buffers (SSD/RAM) | $1,900,000 (Scylla Ring) | $134,400 (Elastic Volumes) | $1,765,600 |
| Data Egress (Internet) | $4,200,000 (Metered Egress) | $20,700 (FastConnect Port) | $4,179,300 |
| Inter-AZ Transfer | $1,120,000 (Cross-AZ Replication) | $0 (Unmetered VCN) | $1,120,000 |
| Object Storage (M1 Archive) | $1,764,000 (Standard S3) | $836,000 (OCI Storage) | $928,000 |
| Total Monthly Baseline | $9,974,000 | $1,009,505 | $8,964,495 |
(Note: Storing 84 PB per month is the primary cost driver across both options. Mitigating this long-term requires volume discounts or data compression strategies, which are outlined in the future roadmap).
graph TD
%% ── Classes ─────────────────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
%% ── Main Header ─────────────────────────────────────────
TotalCost(["Total Monthly Infrastructure Cost: ~$152,907.84<br/>With Month 1 OCI Object Storage: ~$988,907.84"]):::prominent
%% ── Cost Breakdown ──────────────────────────────────────
subgraph PerNode ["1. Per Node Cost ($3,185.58)"]
direction TB
NodeVM["VM (40 OCPU / 128GB RAM)<br/>$383.45"]:::steel
BootVol["Boot Volume<br/>$2.13"]:::sage
NetDisks["8x Network Disks (1525GB, 120 VPU @ $350 each)<br/>$2,800.00"]:::gold
NodeVM --- BootVol --- NetDisks
end
subgraph PerCell ["2. Per Cell Cost ($38,226.96)"]
direction TB
NodeCount["12x Nodes (VM + 8 Disks + Boot Vol)<br/>$38,226.96"]:::crimson
CellDesc["Supports 250k RPS<br/>Distributed across 3 Fault Domains"]:::ghost
NodeCount --- CellDesc
end
subgraph GlobalCost ["3. Global 4-Cell Cost ($152,907.84)"]
direction TB
CellTotal["4x Cells (48 VMs, 384 Disks)<br/>$152,907.84"]:::crimson
GlobalDesc["Supports 1 Million RPS Global Traffic"]:::ghost
CellTotal --- GlobalDesc
end
subgraph NetworkCost ["4. Network Egress"]
direction TB
Egress["84 PB Monthly Egress<br/>via FastConnect Partner<br/>~$20,000 - $30,000<br/>(Not included in total)"]:::sage
end
subgraph StorageCost ["5. Object Storage (Cumulative)"]
direction TB
StorageM1["Month 1 Capacity (at $0.01/GB)<br/>$836,000"]:::crimson
StorageM23["Month 2: ~$1.6M<br/>Month 3: ~$2.5M"]:::crimson
Discount["Requires Deep Enterprise Discount<br/>(Expected 30% - 50% reduction)"]:::ghost
StorageM1 --- StorageM23 --- Discount
end
%% Connections from Total
TotalCost --> PerNode
TotalCost --> PerCell
TotalCost --> GlobalCost
TotalCost --> NetworkCost
TotalCost --> StorageCost
6. Engineering Trade-offs & Challenges
By shifting complexity from off-the-shelf databases to a custom engine, we accepted specific architectural trade-offs:
graph TD
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1.5px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
Title["Architecture 2 Hidden Trade-offs<br>(Trading Database CapEx for Elite Engineering OpEx)"]:::prominent
subgraph Challenges ["The 5 Critical Flaws of a Custom 'Do-It-Yourself' Database"]
direction TB
C1["1. Engineering & Maintenance Trap<br>OS/Kernel friction with rapid disk mounts.<br>Bus Factor of 1-2 (Requires elite low-level systems engineers)."]:::crimson
C2["2. The 'Failsafe' Flaw (Cloud APIs)<br>OCI APIs take 30-90s to mount emergency disks.<br>At 680 MB/s, this forces a ~40GB+ RAM buffer.<br>High risk of Out-of-Memory (OOM) application crashes."]:::crimson
C3["3. Node Death & Data Recovery<br>No native replication or clustering protocol.<br>Node crashes leave 'dirty' orphaned disks behind.<br>Requires manual intervention or fragile custom recovery scripts."]:::crimson
C4["4. Split-Brain Read Nightmare<br>Data is fractured across 4 states at any given moment:<br>Live RAM → 48 Local Disks → In-Flight → Object Storage.<br>Scatter-gather API queries will cause unpredictable read latency."]:::crimson
C5["5. Hidden Financial Tax (Object Storage PUT APIs)<br>1M RPS = 2.59 Trillion requests/month.<br>Unbatched 32KB PUTs to OCI = Millions of $$$ in API fees.<br>Forced large batching (64-128MB) increases data loss risk on crash."]:::crimson
end
Title --> C1
Title --> C2
Title --> C3
Title --> C4
Title --> C5
class Challenges ghost
6.1 The Engineering & Maintenance Trap
Developing a proprietary storage engine increases technical debt. The system requires low-level engineering expertise in Linux kernel internals, virtual memory layout, and system calls (mmap, madvise, msync). This narrow skill requirement increases recruitment costs and limits team scale.
6.2 Cloud API Provisioning Latencies
Using the OCI API to attach emergency block volumes takes 30 to 90 seconds. At a write speed of , a delay of 90 seconds requires the Go application to buffer up to of data in RAM (). If the VM’s memory footprint is mismanaged, this buffer can trigger Out-of-Memory (OOM) kernel panics.
6.3 Recovery after Node Failure
Because the custom engine does not replicate data at the block layer, a node crash leaves its block volumes orphaned in an un-flushed, dirty state.
- Recovery Flow: A recovery script detects the node failure, detaches the orphaned block volumes, and attaches them to a new VM.
- Index Rebuild: The new node reads the raw headers from the disk to reconstruct the B-Tree index, offloads the data to OCI Object Storage, and is then terminated. This restores the system state without data loss, but requires maintaining custom orchestration scripts.
6.4 Split-Brain Read Routing
Because telemetry data is transiting across multiple states (Live RAM, local block volumes, in-flight uploads, and OCI Object Storage), query aggregation requires a routing mapping. The Query Gateway must resolve where target data segments are located, which can cause latency spikes for queries crossing storage tier boundaries.
6.5 API Call Cost Management
Uploading unbatched 32 KB payloads to OCI Object Storage would generate high API fees. To manage costs, the Go application buffers data into 100 GB segments before issuing PUT requests. This reduces transaction fees but increases the amount of un-flushed data buffered in memory.
7. The Future Horizon: C++ Seastar, DPDK, SPDK, and DAOS
As our telemetry network scales from 1,000,000 RPS to 10,000,000 RPS (representing a write load of ), the physical limits of OCI network interfaces will become a bottleneck. We have designed a future architectural roadmap to scale beyond these limits.
flowchart LR
%% ── Dark Elegant Theme ─────────────────────────────────
classDef gold fill:#1f1c15,stroke:#c8a96e,stroke-width:1.5px,color:#e8d5a8
classDef sage fill:#131a14,stroke:#7a9e7e,stroke-width:1px,color:#a8c8ac
classDef steel fill:#131620,stroke:#8896a8,stroke-width:1px,color:#b0bece
classDef crimson fill:#1a1212,stroke:#a87878,stroke-width:1px,color:#d4a0a0
classDef ghost fill:#111110,stroke:#2a2926,stroke-width:1px,color:#6a6860,stroke-dasharray:4 3
classDef prominent fill:#c8a96e,stroke:#c8a96e,color:#1a1508,font-weight:600
subgraph External ["External Ingress (1M RPS)"]
direction TB
GlobalRouter{"DNS / Global LB"}:::gold
NLB["OCI Network Load Balancer<br>(L4 / Direct Routing)"]:::prominent
GlobalRouter --> NLB
end
subgraph ComputeNode ["C++ Compute Tier (DPDK/Seastar Shared-Nothing)"]
direction TB
NIC["OCI 100GbE NIC Hardware<br>(SR-IOV / VFIO-PCI)"]:::steel
Mbuf["Hugepages Memory<br>(rte_mempool / mbuf)"]:::sage
subgraph Cores ["Thread-Per-Core (Pinned CPUs)"]
direction TB
Core1["Core 1: DPDK Rx Ring -> Userspace TCP -> App Logic"]:::gold
Core2["Core 2: DPDK Rx Ring -> Userspace TCP -> App Logic"]:::gold
end
SPDK["SPDK Appender<br>(Direct Local NVMe)"]:::steel
NIC -- "DMA Write" --> Mbuf
Mbuf -. "Pointer Ref" .-> Cores
Cores -- "Pass mbuf (Zero Context Switch)" --> SPDK
end
subgraph Storage ["Storage Fabric (RDMA / RoCEv2)"]
direction TB
DAOS_API["DAOS API (libdaos)<br>Async RDMA Push"]:::prominent
DAOS_Pools[("DAOS Distributed Container<br>(Key-Array 32KB Objects)")]:::gold
S3[("OCI Object Storage<br>(Native Tiering / Archive)")]:::sage
DAOS_API --> DAOS_Pools
DAOS_Pools -- "Zero-Copy Async Flush" --> S3
end
%% Main Data Flow (Left to Right)
NLB -- "Raw Frames<br>(RSS Hashing by IP/Port)" --> NIC
SPDK -- "spdk_thread<br>(Bypass Kernel)" --> DAOS_API
%% Optional layout adjustments to "make it go around" / visually balanced
S3 -. "Metadata / Tiering Status" .-> GlobalRouter
class External,ComputeNode,Cores,Storage ghost
7.1 DPDK-Driven Userspace Networking
- To bypass the Linux kernel TCP/IP stack, we will transition the engine to C++ using the Data Plane Development Kit (DPDK).
- By binding the VNICs to DPDK userspace drivers (
vfio-pci), the application gains direct access to network card ring buffers via Direct Memory Access (DMA). This avoids kernel context switching, page faults, and system call overhead. - We will run a userspace TCP stack pinned to individual CPU cores, using Receive Side Scaling (RSS) to distribute packets without CPU core synchronization.
7.2 SPDK-Driven Direct Block Storage
- To bypass the kernel filesystem layer and SCSI drivers, we will use the Storage Performance Development Kit (SPDK).
- SPDK uses userspace drivers to communicate with NVMe block volumes via PCIe.
- This allows the application to write data blocks directly to raw storage sectors without kernel block device scheduling, reducing write latencies to single-digit microseconds.
7.3 DAOS-Based Storage Fabric
- For persistent storage scaling, we will implement Distributed Asynchronous Object Storage (DAOS).
- DAOS uses Remote Direct Memory Access (RDMA) over Converged Ethernet (RoCEv2) networks. This allows nodes to read and write to shared storage pools without CPU intervention, enabling scalable data replication and tiering.
8. Lessons Learned & Conclusion
- Understand Platform Economics: High-throughput system architecture must be designed alongside cloud billing structures. Selecting a cloud provider based on network and storage pricing (like OCI's egress structure) can be as critical as code efficiency.
- Respect Mechanical Sympathy: At scale, general-purpose software frameworks can introduce significant overhead. Aligning application design with hardware characteristics—such as matching OCI's OCPU count to VNIC bandwidth limits and using
mmapfor disk writes—is essential to maximize performance. - Optimize System Interfaces: Managing large data ingestion requires tuning system-level parameters. Implementing Jumbo Frames (MTU 9000), using Event-Loop reactors, and disabling kernel interrupts are necessary steps to prevent operating system bottlenecks.
True systems architecture requires designing within the bounds of both software physics and cloud financial constraints. By replacing generic database layers with a custom storage engine, we met our performance goals while keeping operational costs within target budgets.
The Impact
We transitioned the infrastructure to Oracle Cloud (OCI) and architected a lock-free, zero-allocation ring buffer. We eliminated the database bottleneck via direct memory-mapped network disks, achieving deterministic scaling while slashing operational expenditures to under $175,000 monthly.
Run this measurement against your own system.
Deployment Audit: £500, fixed scope. Credited in full against the next stage.
What this costs