Docs / Architecture

Built on Rust's Async Ecosystem

A deep dive into the technology stack, operating modes, request lifecycle, and the lock-free concurrency model that makes Ferrum Edge fast.

Core Dependencies

Every dependency was chosen for performance, correctness, and Rust-native design.

tokio
Async Runtime

Multi-threaded async runtime. Work-stealing scheduler maximizes CPU utilization across all cores.

hyper 1.x
HTTP Engine

Production-grade HTTP/1.1 and HTTP/2 implementation. Powers most of Rust's web ecosystem.

rustls
TLS Implementation

Pure-Rust TLS. No OpenSSL dependency, no C FFI, memory-safe TLS for all connections.

tonic
gRPC

gRPC over HTTP/2. Used for both gRPC proxying and the CP→DP control channel.

quinn + h3
HTTP/3 / QUIC

IETF QUIC and HTTP/3 over UDP. 0-RTT connection establishment for repeat clients.

sqlx
Async Database

Compile-time checked SQL queries. Async connection pooling for PostgreSQL, MySQL, and SQLite.

serde
Serialization

Zero-copy deserialization of config, plugin configs, and API payloads. JSON and YAML support.

tracing
Observability

Structured, contextual logging with per-request spans. OpenTelemetry-compatible.

ArcSwap
Lock-Free Config

Atomic reference-counted pointer swaps. Config reads are wait-free. Updates are atomic. The key to zero-downtime reloads.

DashMap
Concurrent Maps

Sharded concurrent hash maps. O(1) lookups with no global lock. Routes, consumers, rate limiters — all DashMap.

jemalloc
Memory Allocator

High-performance allocator on Linux and macOS. Better multi-threaded allocation performance vs. system malloc.

Operating Mode Diagrams

File Mode
YAML Config File
→ load →
Ferrum Edge
:8000 / :8443
→ proxy →
Backends
No database required. Config reloaded via SIGHUP or restart. Admin API is read-only.
Database Mode
DB (PG/MySQL/SQLite/Mongo)
→ poll →
Ferrum Edge
:8000 / :9000
→ proxy →
Backends
Admin API has full CRUD. Config cached in ArcSwap — survives DB outages.
Control Plane / Data Plane Mode
Database
Control Plane
:9000 / :50051
→ gRPC stream →
Data Plane 1
:8000/:8443
Data Plane 2
:8000/:8443
Data Plane N
:8000/:8443
→ proxy →
Backends
CP reads from DB and pushes config to DPs via gRPC streaming. DPs cache config locally. DP auto-reconnects on CP loss. Horizontally scalable — add DP instances without touching CP.
Migrate Mode
Ferrum Edge
ferrum-edge migrate
→ run migrations →
Database
→ exit
Runs database schema migrations then exits. Designed for CI/CD pipelines — no proxy listeners started.

Request Lifecycle

1

Connection Accept

tokio accepts the TCP/UDP connection on the configured port. TLS handshake (rustls) if applicable. Protocol detection via ALPN for HTTP/1.1 vs HTTP/2.

2

Config Load (Lock-Free)

Atomic ArcSwap load. O(1), no blocking. Returns Arc pointer to current config. All concurrent requests share the same config Arc without copying.

3

Route Matching

DashMap lookup by host → sorted route list. Longest prefix match. O(1) average, no linear scans. If no route matches, 404 is returned immediately.

4

Plugin Chain Execution

Plugins execute in priority order: IP restriction → authentication → authorization → transformation → before_proxy. Any plugin can short-circuit by returning a response directly.

5

Upstream Selection

Load balancing algorithm selects a healthy upstream from the pool. Health state checked via atomic bool. Connection acquired from per-host pool.

6

Proxy & Response

Request forwarded via hyper to upstream. Response streamed back through after_proxy plugin hooks. Response body buffered only if a plugin requires it (opt-in).

7

Logging Phase

log() hook called on all plugins. Async, non-blocking. Access logs, metrics, traces emitted. Arc to config dropped — if config was swapped, old version is freed here.

Atomic Config Swap

Config Update Flow (Zero Downtime)
Admin API / DB Poll
Build New Config Object
ArcSwap::swap(new_config)
In-flight requests (before swap)
Hold Arc to old config. Complete normally with old routing/plugins.
New requests (after swap)
Load new Arc. See updated routing and plugin configs immediately.
Old config object is freed when the last in-flight request drops its Arc reference. No double-write, no lock, no downtime.

Data Structure Complexity Table

OperationStructureReadWriteNotes
Config accessArcSwapO(1) atomicO(1) atomic swapWait-free reads
Route lookupDashMapO(1)O(1) shard-locknum_cpus × 4 shards by default
Consumer lookupDashMapO(1)O(1) shard-lockBy API key or consumer ID
Rate limit checkDashMap + AtomicU64O(1)O(1) CASLock-free token bucket
Health stateAtomicBool per targetO(1) atomicO(1) atomicPer upstream target
Plugin lookupDashMapO(1)Build-time onlyPlugins registered once at startup
Load balancing (RR)AtomicUsizeO(1)O(1) fetch_addAtomic counter mod N
Load balancing (hash)Consistent hash ringO(log V)O(N log V)V = virtual nodes (150)
Connection poolDashMap + AtomicU64O(1)O(1) shard-lockLock-free epoch cleanup

Want to Extend the Architecture?

Write a Custom Plugin → Contributing Guide