Replies: 2 comments 1 reply
Cons of Native MQTT
|
|
Welcome @ygndotgg, and thanks for writing this up. One existing pattern worth looking at before choosing: gateways/kafka is a separate crate that runs as its own process, with its own listener and connection limit. The gateways README describes gateways as letting existing clients talk to Iggy without changing the core server wire surface. An MQTT gateway built the same way would sit alongside it. Also richardcocks's point on #4181 about running an existing broker with a connector is also worth considering. |
Uh oh!
There was an error while loading. Please reload this page.
Native MQTT protocol surface for Iggy
Status
Design validation proposal. This document describes a constrained first phase and its long-term architectural boundaries. It does not want to propose full MQTT broker compatibility.
Executive summary
Iggy is an append-only distributed log and message streaming platform. MQTT should therefore be introduced as an isolated protocol and delivery runtime above the existing streaming engine.
The proposed design is:
The initial phase does not modify:
The initial phase supports TCP/TLS, exact topics, clean sessions, QoS 0, and constrained QoS 1. QoS 2, retained messages, wildcard subscriptions, persistent sessions, offline queues, shared subscriptions, and MQTT over WebSocket are deferred.
The central design position is:
1. Strategic context
The primary architectural concern is preventing MQTT-specific semantics from leaking into Iggy's generic streaming core.
MQTT introduces state that does not naturally belong in Iggy's append-only log path:
The separation is important for two reasons:
The goal is not to make every Iggy operation understand MQTT. The goal is to expose MQTT semantics at a protocol boundary while reusing Iggy's existing streaming primitives underneath.
An external MQTT gateway remains a valid alternative. It provides stronger process isolation but adds another deployment unit and network hop. This proposal evaluates the in-process option because it offers direct connectivity and avoids an additional hop while preserving the same semantic boundary as a gateway.
2. Existing Iggy architecture
2.1 Native binary protocols
TCP, TCP-TLS, WebSocket, WSS, and QUIC carry Iggy's native binary protocol.
Relevant code:
The existing TransportConn abstraction is designed for transports that decode Iggy GenericHeader messages. MQTT packets do not have that shape, and MQTT requires long-lived subscription and delivery state. MQTT should therefore be a parallel protocol surface rather than another TransportConn implementation in the first phase.
2.2 HTTP precedent
HTTP already demonstrates that Iggy can host a separate protocol surface:
HTTP does not use the native RequestHandler, but it reuses Iggy's internal operations and storage.
Relevant code:
HTTP is a precedent for protocol-path separation. It does not prove complete resource isolation: HTTP, MQTT, and native traffic still share process CPU, memory, runtime capacity, sockets, and storage resources.
3. Proposed boundary
MQTT receives its own protocol-specific entry point and translates MQTT operations into existing Iggy operations. Native traffic does not enter the MQTT parser.
4. Proposed MQTT architecture
Layer 4 is not modified for MQTT in the initial phase. The server does gain additive runtime code for Layers 1–3.
5. Listener and connection flow
The MQTT listener uses a separate configured address or port.
The native paths remain separate. The separate listener prevents native clients from entering the MQTT parser.
The initial implementation can reuse:
This reuses listener infrastructure without making MQTT an implementation of the native Iggy frame transport.
Milestone 1 assumes a shard-0-resident MQTT listener and session runtime to mirror the existing HTTP/server bootstrap model. This is an explicit initial scalability tradeoff, not a general Iggy runtime guarantee. MQTT sessions are not migrated between shards or nodes in this phase.
6. Configuration and bootstrap changes
A new self-contained MQTT configuration section is required. A location consistent with the current repository is:
The configuration would include, subject to final review:
Configuration integration would likely touch:
Boot integration would mirror the HTTP lifecycle:
The MQTT listener would not initially be registered as a native Iggy transport. It would use its own port and remain outside the existing native transport-discovery contract.
Endpoint discovery decision
Milestone 1 treats MQTT endpoint discovery as an independent deployment/configuration concern.
MQTT clients obtain the endpoint through:
MQTT is not added to TransportPorts, cluster metadata, or the derived native client-listener precedence in Milestone 1.
If future requirements need cluster-advertised MQTT endpoints, the following would need to change:
7. Authentication and identity
The existing server contains reusable authentication and session functions, including:
Relevant code:
The identities must remain distinct:
For the constrained phase, only clean sessions are supported. MQTT Client ID therefore does not restore persistent MQTT state after disconnect or server restart.
Initial authentication mappings may be:
Authorization must be applied independently to:
Some current authentication and authorization helpers are internal to core/server. A protocol-neutral internal facade may need to be extracted rather than duplicating security logic in the MQTT module.
8. Publishing flow
A default mapping could be:
The initial implementation should prefer pre-provisioned Iggy streams/topics or explicit configured mappings. Automatic creation is deferred because it introduces metadata races, permission ambiguity, and unbounded resource creation.
Partition-key selection must be configurable. Possible policies include:
The implementation must not assume that every MQTT topic contains a device identifier.
QoS 1 publishing contract
PUBACK means that the mapped Iggy write reached the completion point defined by Iggy's normal partition semantics. It does not automatically mean that the message has been fsynced to disk, and it does not provide exactly-once delivery.
Retries may produce duplicates. The implementation must preserve MQTT packet identity for the duration of the connection and document duplicate behavior.
9. Consumption and delivery flow
Iggy remains pull-based and MQTT remains push-based. The MQTT runtime acts as a push facade over Iggy polling without changing the partition API.
The key invariant is:
Polling must not advance the durable committed consumer offset before the MQTT client acknowledges delivery.
For MQTT QoS 1 delivery:
The current Iggy API represents the read as:
The auto_commit = false setting belongs to PollingArgs carried by args.
If the client disconnects before acknowledging, redelivery is allowed while the relevant delivery state remains available. Clean-session disconnects do not provide offline redelivery guarantees.
10. Subscription semantics
Milestone 1 supports exact topics only.
Ordinary MQTT subscriptions are fan-out. Iggy consumer groups are load-balancing. Therefore, ordinary MQTT subscribers must not share one Iggy consumer group.
If both clients subscribe to the same MQTT topic, both must receive every matching message. Client A may acknowledge a message while Client B has not, so their delivery positions must advance independently.
Consumer groups may become useful for future MQTT shared subscriptions, but they are not the implementation for ordinary MQTT fan-out.
The implementation must choose between:
This is an implementation decision that should be benchmarked rather than hidden in the initial design.
11. Session model
Milestone 1 supports clean sessions only.
On disconnect:
The runtime still requires connection-local state for:
Persistent MQTT sessions are excluded because they require durable storage for subscriptions, session expiry, pending messages, packet identifiers, redelivery state, and offline queues.
12. Milestone 1 scope
Supported
Excluded
QoS 2
QoS 2 requires durable transaction state for:
That state must survive retransmission, disconnect, node failure, and recovery.
Retained messages
Retained messages require latest-value semantics:
This is different from Iggy's append-only log and should be designed as a separate latest-value or compacted-state subsystem.
Persistent sessions and offline queues
These require durable per-client MQTT state and recovery across restart or failover.
Wildcard subscriptions
Shared subscriptions
These may eventually map to Iggy consumer groups, but they should be specified separately because their delivery semantics differ from ordinary MQTT subscriptions.
MQTT over WebSocket
Existing WebSocket support carries Iggy binary frames. It does not automatically provide MQTT subprotocol negotiation or MQTT packet handling. MQTT over WebSocket can be considered after the TCP/TLS path is validated.
13. Configuration, runtime, and core impact
The initial MQTT phase is not “no change.” It is a moderate server/runtime addition that deliberately avoids modifying the most sensitive storage and consensus components.
14. Performance and safety requirements
The MQTT runtime must bound:
Separate ports provide protocol-path isolation, not complete resource isolation. MQTT and native traffic still share process resources.
The implementation should benchmark at least:
Metrics should cover:
15. Failure and recovery semantics
The first phase should explicitly define these cases:
The first phase provides at-least-once behavior while relevant clean-session state remains available. It does not provide exactly-once delivery or offline recovery.
16. Pros
17. Cons and risks
18. Decisions requested
Before implementation, the following decisions should be confirmed:
Conclusion
MQTT is feasible as a separate protocol and delivery surface within the Iggy server.
The recommended first-phase design is:
The implementation should keep Iggy's native binary path and streaming core unchanged while adding the required MQTT runtime above them.
The main impact is moderate server/runtime work, not a partition or VSR redesign. The highest-risk area is QoS 1 subscription delivery:
The final architectural position is:
All reactions