This article explores a system design for real-time event analytics at the physical edge, focusing on handling high-density crowd data from IoT devices in challenging network environments. It outlines an architecture that leverages localized MQTT brokers and edge nodes for data ingestion, debouncing, and processing to ensure high availability and sub-second metric delivery even without external cloud connectivity. The core idea is to process raw data closer to the source before transmitting it to the cloud.
Read original on Dev.to #systemdesignDesigning real-time analytics for physical spaces with large crowds presents unique challenges compared to virtual web traffic. Network congestion (5G, Wi-Fi), packet loss, and latency spikes are common in high-density environments, making direct cloud streaming unreliable. An effective system must address these physical layer constraints to maintain real-time visibility and data integrity.
The proposed architecture shifts ingress logic to the edge using local micro-servers (edge nodes) running Node.js. Instead of direct cloud API calls, IoT hardware (e.g., RFID antenna arrays) publishes raw data to a local MQTT broker hosted on the venue's intranet. This ensures that data capture and initial processing occur locally, independent of external internet connectivity.
Why MQTT at the Edge?
MQTT is a lightweight, publish-subscribe messaging protocol ideal for IoT and constrained environments. Its low overhead and support for Quality of Service (QoS) levels make it suitable for unreliable networks and edge deployments where bandwidth and power are critical factors.
A critical issue at the physical layer is "tag chatter"—multiple reads for a stationary attendee. The system debounces this data directly at the edge node using a local cache (e.g., Redis). This prevents redundant payloads from overwhelming local networks and processing systems, ensuring only meaningful state changes are propagated. This is an example of applying a common software pattern (debouncing) to a unique hardware/network problem.
const localRedis = require('./local-cache');
async function handlePhysicalTagRead(tagId, antennaId) {
const cacheKey = `tag:${tagId}:location`;
const lastSeenLocation = await localRedis.get(cacheKey);
// If the attendee hasn't changed zones, drop the duplicate payload
if (lastSeenLocation === antennaId) {
return; // Debounced
}
// Update local state immediately for the onsite dashboard
await localRedis.set(cacheKey, antennaId, 'EX', 300);
// Publish to the local broker for real-time heatmap processing
mqttClient.publish('venue/telemetry/flow', JSON.stringify({ uid: tagId, zone: antennaId, ts: Date.now() }), { qos: 1 });
}This local debouncing ensures that the real-time dashboard, fed by the local MQTT broker, receives clean, actionable data. A separate background worker is responsible for batching these local MQTT messages and syncing them to primary cloud databases when external network conditions allow. This provides graceful degradation and offline capabilities for the analytics dashboard.