Clustering
TBMQ scales by adding nodes, and every node is the same as every other: no master, no coordinator, no node holding state the rest depend on. Any client can connect to any node, any node can process any published message — including messages destined for clients connected elsewhere — and losing a node costs you those connections and nothing else.
That symmetry is what makes a TBMQ cluster operationally uninteresting, which is the point. Nodes can be added, restarted or lost without a promotion, a rebalancing procedure, or a configuration change on the surviving nodes.
Standalone vs cluster
Section titled “Standalone vs cluster”There is no cluster mode to switch on: a standalone deployment is a cluster of one, running the same binary against the same dependencies. Scaling out means starting more nodes and putting a load balancer in front of them.
Any TCP load balancer will do, because TBMQ needs no session affinity — a client that lands on a different node than last time still finds its session. See Installation for the cluster deployment guides, and PROXY protocol if the broker has to see real client IP addresses through the balancer.
How nodes stay consistent
Section titled “How nodes stay consistent”Nodes never call each other. Everything one node needs another to know — that a client connected, that a subscription changed, that a message has to be delivered on a different node — goes through Kafka and is read back by whoever needs it. Each node keeps its own in-memory copy of sessions and subscriptions so it can match a published topic without asking anyone, and rebuilds that copy from Kafka on startup before it serves traffic. Redis holds the queued messages of persistent DEVICE clients, and PostgreSQL holds credentials and configuration; neither carries live message traffic between nodes.
The same mechanism enforces the rules that have to hold cluster-wide. MQTT permits one live session per client ID, and TBMQ honours that across the whole cluster: connection events for a given client ID are processed in a single strict sequence, so two clients racing with the same identifier are resolved identically on twenty nodes and on one — with no lock service and no leader election anywhere in the design.
For the components, the shared state, and the exact routing paths between nodes, see the architecture overview.
What a failure looks like
Section titled “What a failure looks like”| What fails | What happens |
|---|---|
| A broker node | Its clients reconnect to any other node; persistent sessions resume there with subscriptions and queued messages intact, and unacknowledged QoS 1 and QoS 2 messages are redelivered. |
| A Kafka node | Processing pauses while the surviving nodes take over the affected partitions, then resumes from the last committed position — messages already handled but not yet committed may be redelivered. Run Kafka replicated; the shipped defaults keep a single copy. |
| A Redis node | Offline delivery for persistent DEVICE clients pauses until a replica is promoted. Configure replication here too. |
TBMQ itself contains no single point of failure. The failure modes that matter are the shared dependencies, so those are what to make redundant first — and both of the pauses above are pauses, not losses, once replication is in place.
Scaling guidelines
Section titled “Scaling guidelines”- Add broker nodes when connection count, CPU, or per-node throughput is the constraint. They join on their own, with no restart of the existing nodes.
- Scale Kafka when message ingestion is the constraint: more parallelism there is what allows more broker nodes to consume in parallel, so the two are scaled together.
- Scale Redis when the volume of offline messages held for persistent DEVICE clients is the constraint.
- Leave PostgreSQL for last. It holds metadata and credentials rather than the message path, so it is rarely the first thing to run out.
The three traffic patterns TBMQ is built for — fan-in, fan-out and point-to-point — load a cluster differently; see Why TBMQ for the reasoning and performance reference for the measured results.
Was this helpful?