Skip to content

Cluster Architecture

The Monibuca V6 cluster solution is based on the Origin-Edge model. Nodes communicate via the QUIC protocol for low-latency, high-reliability communication, supporting automatic node discovery, intelligent stream forwarding, and load balancing.

flowchart TB
  DNS["DNS/LB<br/>User Entry Point"]
  DNS --> EBJ["Edge-BJ<br/>Beijing"]
  DNS --> ESH["Edge-SH<br/>Shanghai"]
  DNS --> EGZ["Edge-GZ<br/>Guangzhou"]
  subgraph OC["Origin Cluster"]
    O1["Origin-1"]
    O2["Origin-2"]
    O3["Origin-3"]
  end
  EBJ -->|QUIC Relay| OC
  ESH -->|QUIC Relay| OC
  EGZ -->|QUIC Relay| OC
RoleResponsibility
OriginReceives direct ingest from publishers; serves as the stream source. Provides stream data to Edge nodes
EdgeReceives pull requests from viewers. Automatically pulls from Origin when a stream is not available locally

Cluster nodes communicate using the QUIC protocol, leveraging its inherent advantages:

FeatureTCPQUIC
Connection establishment1-3 RTT (including TLS)0-1 RTT
Head-of-line blockingEntire connection blockedOnly individual stream blocked
MultiplexingRequires HTTP/2Native support
Connection migrationNot supportedSupported (survives IP changes)
Congestion controlShared across connectionIndependent per stream
flowchart TB
  App["Application Layer<br/>HTTP /cluster/api control"]
  Relay["Relay Layer<br/>Audio/Video Data Transfer"]
  Quic["QUIC Transport<br/>quinn Connection Mgmt"]
  Tls["TLS 1.3<br/>Self-signed / Auto Certs"]
  App --> Relay --> Quic --> Tls
  • HTTP control plane: Discovery, heartbeats (POST /cluster/api/heartbeat), node/session APIs; use cluster.sync.address / seed_servers on the same port as global.http.listenaddr (default 8180)
  • Relay Layer: High-speed audio/video frame data transfer, transmitted directly over QUIC streams
  • Transport Layer: QUIC connection management based on the quinn library, with automatic certificate generation

When a new node starts, it connects to the seed nodes configured in seed_servers to obtain cluster topology information:

sequenceDiagram
  participant N as New Node
  participant S as Seed Node
  participant O as Each Node
  N->>S: I am edge-3, please tell me who is in the cluster
  S->>N: origin-1, edge-1, edge-2, ...
  N->>O: Establish QUIC connections
sequenceDiagram
  participant A as Node A
  participant B as Node B
  A->>B: heartbeat (every 5s)
  B->>A: heartbeat_ack

Each heartbeat carries node summary information:

  • CPU usage
  • Memory usage
  • Bandwidth usage
  • Current stream count
  • Subscriber count

Three-level failure detection based on heartbeat timeout:

StateConditionBehavior
HealthyHeartbeat normalParticipates in cluster normally
Suspectsuspect_threshold consecutive missed responsesMarked as suspect, weight reduced
Offlineoffline_threshold consecutive missed responsesMarked as offline, sessions cleaned up

When a node is marked as Offline, the following actions are triggered:

  1. SessionRegistry clears all stream registrations for that node
  2. RelayManager disconnects all Relay connections to that node
  3. AllocationManager stops assigning requests to that node
sequenceDiagram
  participant V as Viewer
  participant E as Edge
  participant Reg as SessionRegistry
  participant O as Origin-1
  V->>E: Request live/camera01
  Note over E: Stream not available locally, query SessionRegistry
  Reg->>E: Stream is on Origin-1
  E->>O: Establish QUIC Relay connection
  O->>E: Transfer audio/video data via QUIC
  E->>V: Distribute to local subscribers
  1. Establishment: Edge detects no local stream and initiates a Relay request to Origin via QUIC
  2. Transfer: RingBuffer data from Origin is transmitted to Edge over QUIC streams
  3. Health Check: Relay connection status is periodically checked (every health_check_interval seconds)
  4. Release: After the last subscriber on the Edge leaves, the Relay is released after waiting release_delay seconds

When a Relay connection is broken:

  1. RelayManager detects the connection anomaly
  2. Waits retry_delay seconds before retrying
  3. Retries up to max_retry_attempts times
  4. If the Origin node is offline, queries SessionRegistry for a new Origin
  5. After all retries fail, the stream on the Edge is marked as unavailable

AllocationManager selects the optimal node for new requests via POST /cluster/api/allocate/publish|play, considering:

  1. Node health status: Only selects nodes in Online state
  2. Load metrics: Weighted scoring over CPU usage, memory, bandwidth, stream count, and latency

allocate/play also attaches origin hints from the session catalog (origin_server_id / origin_addr / origin_quic_addr / relay_required) so the caller knows whether playing on the chosen node will trigger an Edge relay pull from origin.

When the local node’s load exceeds the thresholds, GET /cluster/api/redirect/decision suggests a better node (should_redirect / target / candidates, plus the same origin hint fields):

sequenceDiagram
  participant C as Caller
  participant E as Edge-BJ
  C->>E: GET /cluster/api/redirect/decision?stream_path=live/camera01
  Note over E: CPU 90% exceeds threshold 85%
  E->>C: should_redirect=true, target=edge-sh
  Note over C: Point viewer at Edge-SH media endpoint

Redirect threshold configuration:

cluster:
routing:
cpu_threshold: 85.0 # CPU usage threshold
bandwidth_threshold: 8000.0 # Bandwidth threshold (Mbps)
subscriber_threshold: 2000 # Subscriber count threshold

The most common deployment mode, suitable for small to medium scale:

# Origin configuration
cluster:
sync:
server_id: "origin-1"
address: "10.0.1.1:8180"
seed_servers: ["10.0.1.1:8180"]
# Edge configuration
cluster:
sync:
server_id: "edge-bj-1"
address: "10.0.2.1:8180"
seed_servers: ["10.0.1.1:8180"] # Points to Origin

Large-scale deployment with multiple Origins sharing the ingest load:

# Origin-1
cluster:
sync:
server_id: "origin-1"
address: "10.0.1.1:8180"
seed_servers: ["10.0.1.1:8180", "10.0.1.2:8180"]
# Origin-2
cluster:
sync:
server_id: "origin-2"
address: "10.0.1.2:8180"
seed_servers: ["10.0.1.1:8180", "10.0.1.2:8180"]
# Edge
cluster:
sync:
server_id: "edge-1"
address: "10.0.2.1:8180"
seed_servers: ["10.0.1.1:8180", "10.0.1.2:8180"]

Edge nodes can also serve as upstream for other Edges, forming a multi-tier cascade:

flowchart LR
  Ingest["Ingest"] --> Origin --> L1["Edge-L1<br/>Regional Hub"] --> L2["Edge-L2<br/>City Node"] --> Viewer["Viewer"]

Suitable for large-scale nationwide distribution scenarios.

Cluster HTTP APIs live under /cluster/api/ on global.http.listenaddr (not gRPC global.tcp).

GET /cluster/api/status/local
GET /cluster/api/servers
GET /cluster/api/sessions
GET /cluster/api/relay/sessions

The Admin Cluster page derives alerts and Origin→relay topology from current snapshots of these endpoints (30s polling); it is not a historical event store.

See the Cluster plugin doc for the full API list.