linusdm
Ingesting stream of MQTT events with Flow. Is it a good idea?
Hey folks,
I’m trying to figure out how to ingest a stream of messages from an MQTT broker in an efficient way. The problem involves many different sensors that publish a measurement once every minute. A server (one node for now) subscribes to these messages and picks these messages up from the broker. The stream of messages should be partitioned by sensor (so one stream of messages un-bundles into many streams, one for each sensor) so they can be processed separately. Then it would be desirable to have all messages accumulated every period of ten minutes, before they can be handed over to the business logic. The business logic is encapsulated in an OTP process (a GenServer for each sensor). The accumulation is required to calculate an average out of the ten measurements that arrived in each window.
As I’m reading Concurrent Data Processing in Elixir I’m trying to bend my head over this problem and see how my envisioned system maps onto concepts of the Flow library. I’m excluding Broadway here, because I can’t find a mature library that acts as a Broadway producer from an MQTT broker.
Am I on the right track with this? Is Flow a good fit for this use-case? Or is this better solved in the Functional Core (I’m borrowing terms from the Designing Elixir Systems with OTP book). Will Flow allow me to partition(?) the data per sensor, and create windows (or maybe I need triggers here) for each interval of ten minutes, after which I can emit the received messages once the period has passed?
I’m having a hard time understanding the Flow concepts, but I’m getting there (I have read the hexdocs five times by now).
Most Liked
tcoopman
How many sensors are we talking about? Emitting once every minute is slow enough that you should only worry about performance and partitioning if there are enough sensors.
Also what should happen if something fails? Is it ok if you drop messages? What should happen if after 6 minutes your accumulation logic crashes. Is it ok to just restart from the current message or do you need to restart from the first message?
Do you need to store all incoming data for later usage? Or can you just drop it. What about the accumulation, do you need to store that or just emit it somewhere?
These would be the kind of questions I’d ask myself before making a decision on anything. Because they will affect how you want to design your solution.
Depending on some of the answers to the above question. I’d probably start with a MQTT client and handle the logic myself. I don’t know flow so I can’t comment if it would be a good choice for you.
Sebb
If you do not need the actual values the time series database can do the aggregation. You can then pull from the DB, which will simplify the architecture.
tcoopman
Can you save your accumulation after every message or only after 10 messages? Because that will make a big difference if you can let the broker handle unacknowledged messages or not. Basically if you save accumulation after every message then you can acknowledge right after saving. In the other case you’d need to wait 10 minutes. that’s something the message broker probably doesn’t support…
A time series database might definitely be worth looking at, but for me it would depend if the added complexity of the extra database (although there are postgres extensions as well) is worth it.
I’ve built something similarly in the past. With rabbitMq and postgres. I could easily handle 1000s msg/sec on a fairly regular server. Don’t remember the exact details but nothing very beefy was needed.
derpycoder
Use Shared Subscription
Shared subscriptions are an MQTT v5 feature that allows MQTT clients to share the same subscription on the broker. In standard MQTT subscriptions, each subscribing client receives a copy of each message that is sent to that topic. In a shared subscription, all clients that share the same subscription in the same subscription group receive messages in an alternating fashion. This mechanism is sometimes called client load balancing , since the message load of a single topic is distributed across all subscribers.

Along with HiveMQ
Reliable Data Movement
for Connected Devices
HiveMQ’s MQTT broker makes it easy to move data to and from connected devices in an efficient, fast and reliable manner.
HiveMQ is architected for scale and reliability. MQTT broker scales up to 10 million connected devices and uses industry standards to ensure data is not lost.
Followed by Genstage based Flow
To intercept and perform business logic before storage.
Use Clickhouse for Timeseries storage
It’s an OLAP + Time series db, faster than Timescale & Influx DB.
See: Benchmark
derpycoder
Definitely use Broadway
They solved the problems that arose after people started building complex GenStage applications.
- Rate Limiting
- Batching
- Metrics
- Graceful shutdown
- Automatic acknowledgement at the end of the pipeline
- Fault tolerance with minimal data loss
- Backpressure
- Concurrency









