Architecture
This guide describes the internal architecture of VibeMQ and its operating principles.
Architecture Overview
VibeMQ is built on a modular principle and consists of several independent components that interact through clearly defined interfaces.
┌─────────────────────────────────────────────────────────────┐
│ VibeMQ.Server │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │TCP Server│◄─┤Connection │◄─┤Queue Manager │ │
│ │ │ │Manager │ │ - Queues │ │
│ └──────────┘ │ - Clients │ │ - Subscriptions │ │
│ │ - Health │ │ - Delivery modes │ │
│ └──────────────┘ └────────────────────┘ │
│ │ │ │
│ ┌───────────▼────────────────▼───────────┐ │
│ │ Command Dispatcher │ │
│ │ - ConnectHandler │ │
│ │ - PublishHandler │ │
│ │ - SubscribeHandler │ │
│ │ - AckHandler │ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────▼────────────────────┐ │
│ │ Delivery Infrastructure │ │
│ │ - AckTracker (retry logic) │ │
│ │ - DeadLetterQueue │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌──────────────────────┼──────────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Client 1 │ │ Client 2 │ │ Client 3 │
│(Publisher)│ │(Subscriber)│ │(Subscriber)│
└───────────┘ └───────────┘ └───────────┘
System Components
VibeMQ.Core
Purpose: Basic models, interfaces, and configuration.
Main types:
Type |
Description |
|---|---|
|
Broker message model |
|
Queue state information |
|
Server configuration |
|
Queue settings |
|
Client settings |
|
Queue management interface |
|
Message store interface |
|
Authentication interface |
|
Metrics collection interface |
Enumerations:
DeliveryMode— delivery mode (RoundRobin, FanOut, Priority)MessagePriority— message priority (Low, Normal, High, Critical)OverflowStrategy— overflow strategyFailureReason— failure reasonCommandType— protocol command type
VibeMQ.Protocol
Purpose: Message serialization and TCP transmission.
Framing:
Uses length-prefix approach for message separation in TCP stream:
[4 bytes: length in Big Endian][N bytes: UTF-8 JSON body]
Components:
FrameReader— read frames from streamFrameWriter— write frames to streamWriteBatcher— message batching for performanceProtocolMessage— base class for protocol message
Message format:
{
"id": "msg_123",
"type": "publish",
"queue": "notifications",
"payload": {"title": "Hello", "body": "World"},
"headers": {
"priority": "high",
"correlationId": "corr_456"
},
"schemaVersion": "1.0"
}
VibeMQ.Server
Purpose: Broker server implementation.
Key components:
BrokerServer — main server class:
public sealed partial class BrokerServer : IAsyncDisposable {
public IBrokerMetrics Metrics { get; }
public int ActiveConnections { get; }
public int InFlightMessages { get; }
public Task RunAsync(CancellationToken cancellationToken = default);
public Task StopAsync(CancellationToken cancellationToken = default);
public ValueTask DisposeAsync();
}
BrokerBuilder — Fluent API for configuration:
var broker = BrokerBuilder.Create()
.UsePort(2925)
.UseAuthentication("token")
.ConfigureQueues(options => { ... })
.Build();
QueueManager — queue management:
Queue creation and deletion
Message publishing
Client subscription and unsubscription
Message acknowledgment
ConnectionManager — connection management:
Active connection tracking
Message routing to subscribers
Connection lifecycle management
CommandDispatcher — command handling:
ConnectHandler— connection establishmentPublishHandler— message publishingSubscribeHandler— queue subscriptionUnsubscribeHandler— queue unsubscriptionAckHandler— acknowledgment handlingPingHandler— keep-alive
AckTracker — acknowledgment tracking:
Unacknowledged message tracking
Timeouts and retry attempts
Exponential backoff between retries
DeadLetterQueue — failed message queue:
Store messages with failed delivery
Re-processing mechanism
RateLimiter — rate limiting:
IP-based rate limiting for connections
Client-based rate limiting for messages
VibeMQ.Client
Purpose: Client for broker connection.
VibeMQClient — main client class:
public sealed partial class VibeMQClient : IAsyncDisposable {
public bool IsConnected { get; }
public static Task<VibeMQClient> ConnectAsync(...);
public Task PublishAsync<T>(string queueName, T payload, ...);
public Task<IAsyncDisposable> SubscribeAsync<T>(...);
public Task UnsubscribeAsync(string queueName, ...);
public Task DisconnectAsync(...);
public ValueTask DisposeAsync();
}
ReconnectPolicy — reconnection policy:
public sealed class ReconnectPolicy {
public int MaxAttempts { get; set; } = int.MaxValue;
public TimeSpan InitialDelay { get; set; } = TimeSpan.FromSeconds(1);
public TimeSpan MaxDelay { get; set; } = TimeSpan.FromMinutes(5);
public bool UseExponentialBackoff { get; set; } = true;
public TimeSpan GetDelay(int attempt);
}
VibeMQ.Health
Purpose: HTTP server for health checks.
HealthCheckServer — HTTP server:
public sealed partial class HealthCheckServer : IAsyncDisposable {
public void Start();
public ValueTask DisposeAsync();
}
Endpoints:
GET /health/— health status (200 OK or 503)GET /metrics/— broker metrics (JSON)
HealthStatus — health status:
{
"isHealthy": true,
"status": "healthy",
"activeConnections": 15,
"queueCount": 5,
"inFlightMessages": 42,
"totalMessagesPublished": 125000,
"totalMessagesDelivered": 124850,
"memoryUsageMb": 256,
"timestamp": "2026-02-18T10:30:00Z"
}
Operating Principles
Message Lifecycle
Publishing:
Client sends
PublishcommandServer validates message
Message is stored in queue
PublishAckconfirmation is sent
Routing:
QueueManagerdetermines delivery modeFor Round-robin, next subscriber is selected
For Fan-out, message is copied to all subscribers
For Priority-based, sorted by priority
Delivery:
Message is sent to subscriber via
DelivercommandACK wait timer is started
Message is marked as “in-flight”
Acknowledgment:
Subscriber sends
AckcommandAckTrackermarks message as deliveredMessage is removed from in-flight
Metrics are updated
Retry (if no ACK):
Timer expires
Attempt counter is incremented
If attempts not exhausted — resend
If exhausted — move to Dead Letter Queue
Delivery Modes
Round-robin:
Publisher → Queue → Subscriber 1 (message 1)
→ Subscriber 2 (message 2)
→ Subscriber 1 (message 3)
→ Subscriber 2 (message 4)
Each message is delivered to one subscriber cyclically.
Fan-out with acknowledgment:
Publisher → Queue → Subscriber 1 (copy 1, ACK required)
→ Subscriber 2 (copy 1, ACK required)
→ Subscriber 3 (copy 1, ACK required)
Message is delivered to all subscribers, each must acknowledge.
Fan-out without acknowledgment:
Publisher → Queue → Subscriber 1 (copy 1)
→ Subscriber 2 (copy 1)
→ Subscriber 3 (copy 1)
Message is delivered to all without acknowledgment.
Priority-based:
Queue: [Critical:1] [High:2] [High:3] [Normal:4] [Low:5]
Delivery: Critical → High → High → Normal → Low
Messages are delivered by priority.
Keep-alive Mechanism
PING/PONG mechanism is used to maintain active connections:
Client Server
│ │
│────── PING (every 30s) ─────▶│
│ │
│◀───── PONG (immediate) ─────│
│ │
If server doesn’t receive PING within timeout, connection is closed.
Automatic Reconnections
Client automatically reconnects on connection loss:
Attempt 1: wait 1s
Attempt 2: wait 2s
Attempt 3: wait 4s
Attempt 4: wait 8s
Attempt 5: wait 16s
...
Attempt N: wait 5min (maximum)
Exponential backoff is used with 5 minute maximum.
Graceful Shutdown
On server stop, graceful shutdown is performed:
Stop accepting new connections
Send shutdown notification to clients
Wait for in-flight message processing (up to 30s)
Close all connections
Clean up resources
Memory Management
Backpressure
When memory usage reaches high level:
Watermark 80%: Backpressure enabled
Watermark 90%: New publications blocked
Watermark 95%: Overflow strategy applied
Overflow strategies:
DropOldest — drop oldest message
DropNewest — reject new message
BlockPublisher — block publisher
RedirectToDlq — redirect to DLQ
Object Pool
Protocol message object pool is used to reduce allocations on hot paths (publish/deliver):
public static class ProtocolMessagePool {
private static readonly ConcurrentBag<ProtocolMessage> _pool = new();
public static ProtocolMessage Rent(CommandType type) { ... }
public static void Return(ProtocolMessage message) { ... }
}
Metrics and Monitoring
Collected metrics:
Counters:
TotalMessagesPublished— total publishedTotalMessagesDelivered— total deliveredTotalMessagesAcknowledged— total acknowledgedTotalRetries— total retriesTotalDeadLettered— total in DLQTotalErrors— total errorsTotalConnectionsAccepted— total connectionsTotalConnectionsRejected— total rejections
Gauge metrics:
ActiveConnections— active connectionsActiveQueues— active queuesInFlightMessages— in-flight messagesMemoryUsageBytes— memory usage
Latency:
AverageDeliveryLatencyMs— average delivery latency
Next Steps
Features — detailed feature overview
Communication Protocol — communication protocol details
Monitoring — monitoring and metrics