System Architecture

High-throughput event processing pipeline for real-time market data distribution

Data Flow Pipeline

The system models a complete market data distribution pipeline — from simulated exchange feeds through queue-based ingestion to real-time client broadcast. Each stage is designed for maximum throughput with controlled backpressure.

┌─────────────────────────────────┐ │ Market Feed Simulator │ Produces 200–20K msgs/sec │ (Multiple Exchange Sources) │ Random walk + configurable volatility └──────────────┬──────────────────┘ │ TryWrite (lock-free) ▼ ┌─────────────────────────────────┐ │ Bounded Channel<TradeSignal> │ Capacity: 10,000 │ (Backpressure Queue) │ FullMode: DropOldest │ │ SingleReader: true │ │ SingleWriter: false └──────────────┬──────────────────┘ │ ReadAllAsync (IAsyncEnumerable) ▼ ┌─────────────────────────────────┐ │ Signal Processing Engine │ Batch drain (up to 50 per cycle) │ (TradeQueueProcessor) │ Latency measurement per batch │ │ Interlocked counters (lock-free) └──────────────┬──────────────────┘ │ SendAsync (SignalR) ▼ ┌─────────────────────────────────┐ │ Real-time Broadcast Hub │ WebSocket transport │ (SignalR Hub) │ Per-symbol group subscriptions │ │ Binary MessagePack option └──────────────┬──────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ Trading Terminal UI │ 60-row signal feed (bounded DOM) │ (Browser Clients) │ Virtual ticker tape │ │ Order flow aggregation └─────────────────────────────────┘

Key Design Decisions

DECISION RATIONALE TRADING RELEVANCE
Bounded Channel (10K) Prevents unbounded memory growth; mirrors Service Bus queue semantics Exchange feeds can burst; must handle without OOM
DropOldest policy Stale market data is worthless — always prefer newest quotes Unlike e-commerce where order matters, trading needs freshness
SingleReader=true Enables internal optimizations; guarantees ordering within consumer Trade sequence order matters for audit trails
Batch drain (50) Amortizes syscall and serialization overhead across messages Mirrors Service Bus PeekLock batch receive patterns
Interlocked counters Lock-free stats on the hot path; no mutex contention Critical when processing >10K msgs/sec
ArrayPool for metrics Percentile computation without GC pressure GC pauses are unacceptable in latency-sensitive paths

Latency Budget

End-to-end latency from event generation to client receipt, broken down by stage:

ENQUEUE
<1
microsecond (TryWrite)
QUEUE WAIT
~50
microseconds (avg)
BATCH PROCESS
100–500
microseconds per batch
SIGNALR SEND
1–5
milliseconds (network)
CLIENT RENDER
<16
milliseconds (60fps target)
E2E TARGET
<20
milliseconds total

Scaling Strategy

The architecture scales horizontally at each layer:

  • Feed ingestion: Multiple simulator instances can write concurrently (SingleWriter=false). In production, each exchange connection is a separate producer thread.
  • Queue processing: Single consumer with batch drain achieves >20K msgs/sec. For higher throughput, partition by symbol hash across multiple Channel instances.
  • Broadcast: SignalR supports Azure SignalR Service backplane for horizontal scale-out across multiple app instances.
  • Client fanout: Per-symbol group subscriptions mean clients only receive data they need — reducing bandwidth proportionally.

Failure Handling

FAILURE MODE BEHAVIOR RECOVERY
Queue full (backpressure) DropOldest — newest data preserved Automatic; counter incremented for observability
Client disconnect SignalR automatic reconnect (0s, 1s, 2s, 5s, 10s) Client resumes subscription; missed data is acceptable (live feed)
Exchange disconnect (simulated) Feed pauses; queue drains existing messages Reconnect resumes feed; UI shows disconnect indicator
Consumer crash Channel buffers up to 10K messages Hosted service restarts; buffer provides grace period

Deployment Topology

┌──────────────────────────────────────────────────────────┐ │ Azure Container Apps Environment │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Container: tradedemo-api │ │ │ │ ┌──────────────┐ ┌───────────────────────────┐ │ │ │ │ │ ASP.NET Core │ │ Background Services │ │ │ │ │ │ (Kestrel) │ │ - MarketDataSimulator │ │ │ │ │ │ - SignalR Hub│ │ - TradeQueueProcessor │ │ │ │ │ │ - Static UI │ │ - PerformanceMetrics │ │ │ │ │ │ - REST API │ │ │ │ │ │ │ └──────────────┘ └───────────────────────────┘ │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ ┌───────────────────────▼────────────────────────────┐ │ │ │ Log Analytics Workspace │ │ │ │ (Structured logs, metrics, traces) │ │ │ └────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────┐ │ Azure Service Bus │ │ Queue: market-events │ │ (Production path) │ └──────────────────────────┘