Architecture Review: IoT Telemetry Ingestion Platform
A high-rate device telemetry ingestion architecture designed for millions of devices emitting metrics at 1–60 second intervals. Kafka absorbs device writes as an ingestion buffer, decoupling device-facing ingest endpoints from the storage write path so that downstream storage pressure never propagates back to devices. TimescaleDB provides time-series storage with automatic chunk partitioning by time range, native compression, and continuous aggregate views for rollup queries. ClickHouse serves as the OLAP layer for device fleet analytics queries. Redis caches last-known device state (current readings per device) for real-time alerting queries that must not scan historical storage. Backpressure on the Kafka consumer side prevents storage write throughput from being overwhelmed by burst ingestion events from device reconnect storms.
Evidence Confidence
Moderate
strong
Executive Summary
IoT Telemetry Ingestion Platform: moderate operational readiness (81% evidence confidence). 0 architectural strengths identified, 6 operational risks to manage. Primary concern: Hot Partition. Requires Advanced operational maturity.
Readiness Rationale
Overall moderate readiness across 8 dimensions. Limited: team maturity. Strong: migration, observability, failure recovery.
Key Concerns
- !Hot Partition
- !Write Amplification Cascade
Key Strengths
- +Architecture is well-defined for the write heavy application problem profile
8
Assessments
3
Tradeoffs
6
Sections
11
Recommendations
Readiness Assessments
8Architectural Tradeoffs
3Recommendations
11Monitor: Hot Partition
risk_monitoringOne partition (a database shard, a Kafka topic partition, a Redis hash slot) receives traffic so far above its peers that it saturates while the others sit idle. Aggregate capacity looks healthy, but the hot partition throttles or lags, and everything routed to it degrades. The cause is skew in how keys map to partitions, and the fix depends on whether the skew is spread across many keys or concentrated in one.
Affects 0 nodes
Monitor: Write Amplification Cascade
risk_monitoringEach logical application write triggers multiple physical writes through index maintenance, WAL generation, MVCC versioning, and replication, causing actual disk IOPS to exceed the provisioned I/O ceiling while the logical write rate appears modest.
Affects 0 nodes
Implement: Monitor generic risk probe signals
observabilitySeed 'WAL Saturation Risk Probe' identifies 2 metrics relevant to wal_saturation.
Metrics to instrument: error_rate, p95_latency_ms
Direct device writes to PostgreSQL with time-range partitioning → Kafka ingestion buffer + TimescaleDB consumer writers
migration_planningTrigger: PostgreSQL write p99 > 100ms at sustained device fleet load; device write errors spiking during reconnect events (devices cannot block on write failure); time-range partition pruning queries slow due to too many manual partitions; need for native rollup views without manual aggregation jobs. Migrate from 'Direct device writes to PostgreSQL with time-range partitioning' to 'Kafka ingestion buffer + TimescaleDB consumer writers'. Deploy Kafka ingest endpoint alongside the existing PostgreSQL direct write path. Run both in parallel for 2 weeks with a 10% traffic canary to TimescaleDB, validating that data arrives correctly and rollup views are accurate before migrating 100% of device traffic to the Kafka path.
Kafka introduces an ingestion buffer that makes device data available in storage with 1–5 second lag; real-time alerting systems reading from TimescaleDB must tolerate this latency or migrate to Redis last-known-value reads; TimescaleDB continuous aggregate refresh policy must be configured before production use; unconfigured refresh means rollup views are never updated
TimescaleDB as sole query layer for both real-time and historical queries → Redis last-known-value cache for real-time queries + TimescaleDB for historical queries
migration_planningTrigger: Alerting system query latency > 500ms due to TimescaleDB query execution on current time chunk under write pressure; alert evaluation falling behind schedule; real-time dashboard queries competing with batch analytics queries on same TimescaleDB instance. Migrate from 'TimescaleDB as sole query layer for both real-time and historical queries' to 'Redis last-known-value cache for real-time queries + TimescaleDB for historical queries'. Write to Redis last-known-value in the Kafka consumer before writing to TimescaleDB. This ensures Redis is always as current as TimescaleDB or more current. The alerting system migrates to Redis reads incrementally, one alert rule at a time, with comparison validation against TimescaleDB during the transition period.
Redis last-known-value may lag TimescaleDB by up to Kafka consumer latency (1–5s); alerting systems must tolerate this latency window and must not treat a stale Redis value as ground truth for historical analysis; Redis key schema for device state must be defined once and treated as a contract; changes to the schema require coordinated deploy of both the Kafka consumer (writer) and alerting system (reader)
Prepare runbook for: Burst Traffic Cold Cache Stampede
simulation_preparednessSimulation demonstrates critical degradation of redis, postgresql
Without a runbook, recovery from this failure mode will be ad-hoc
Prepare runbook for: Connection Pool Exhaustion with Horizontal User Scale
simulation_preparednessSimulation demonstrates critical degradation of postgresql
Without a runbook, recovery from this failure mode will be ad-hoc
Plan evolution: OLTP Analytics Queries → OLTP + OLAP Separation
evolution_planningEvolution from Unified OLTP + Analytics on PostgreSQL → Separated OLTP (PostgreSQL) + OLAP (ClickHouse/Snowflake)
Migration complexity: medium. Rollback: always.
Plan evolution: Single Cache Layer → Distributed Cache
evolution_planningEvolution from Single Redis Node / Sentinel Cluster → Distributed Redis Cluster (Consistent Hash Ring)
Migration complexity: medium. Rollback: complex.
Monitor threshold: Tier 1: TimescaleDB Write Throughput Ceiling
scaling_monitoringSignal: TimescaleDB write latency p99 > 50ms for batch INSERT operations; pg_stat_activity showing wait events on WAL flush; TimescaleDB active chunk autovacuum running continuously; Kafka consumer group lag for storage writers growing steadily at baseline (non-storm) load
Bottleneck: TimescaleDB single-node write throughput ceiling (~50k–100k rows/second depending on row width and chunk size configuration). Evolution: Tune TimescaleDB chunk_time_interval to match write cadence (smaller chunks = faster compression, lower WAL amplification per chunk); enable native compression on chunks older than 1 hour to reduce on-disk footprint; add a dedicated NVMe volume for WAL separate from data directory; consider TimescaleDB multi-node for horizontal write distribution across data nodes
Monitor threshold: Tier 2: Kafka Consumer Lag from Reconnect Storm
scaling_monitoringSignal: Kafka consumer group lag jumping from baseline (<100k) to >10M messages within minutes; Kafka broker disk write rate elevated; TimescaleDB write thread pool fully saturated; Redis last-known-value update latency acceptable but historical storage significantly behind real-time; device reconnect event visible in device authentication logs correlating with lag spike
Bottleneck: Kafka consumer pool sized for steady-state throughput, not burst from device reconnect storm; insufficient storage writer parallelism for burst absorption. Evolution: Pre-scale storage writer consumer replicas before anticipated high-risk windows (maintenance events, regional failovers); implement burst-aware consumer scaling using consumer group lag as the autoscale signal; tune Kafka consumer max.poll.records to batch storage INSERTs into TimescaleDB for higher per-consumer throughput (target 500–1000 rows per INSERT batch rather than single-row inserts)
Scaling Pressure Signals
8TimescaleDB write latency p99 > 50ms for batch INSERT operations; pg_stat_activity showing wait events on WAL flush; TimescaleDB active chunk autovacuum running continuously; Kafka consumer group lag for storage writers growing steadily at baseline (non-storm) load
Threshold
Tier 1: TimescaleDB Write Throughput Ceiling
Likely Bottleneck
TimescaleDB single-node write throughput ceiling (~50k–100k rows/second depending on row width and chunk size configuration)
Recommended Evolution
Tune TimescaleDB chunk_time_interval to match write cadence (smaller chunks = faster compression, lower WAL amplification per chunk); enable native compression on chunks older than 1 hour to reduce on-disk footprint; add a dedicated NVMe volume for WAL separate from data directory; consider TimescaleDB multi-node for horizontal write distribution across data nodes
Kafka consumer group lag jumping from baseline (<100k) to >10M messages within minutes; Kafka broker disk write rate elevated; TimescaleDB write thread pool fully saturated; Redis last-known-value update latency acceptable but historical storage significantly behind real-time; device reconnect event visible in device authentication logs correlating with lag spike
Threshold
Tier 2: Kafka Consumer Lag from Reconnect Storm
Likely Bottleneck
Kafka consumer pool sized for steady-state throughput, not burst from device reconnect storm; insufficient storage writer parallelism for burst absorption
Recommended Evolution
Pre-scale storage writer consumer replicas before anticipated high-risk windows (maintenance events, regional failovers); implement burst-aware consumer scaling using consumer group lag as the autoscale signal; tune Kafka consumer max.poll.records to batch storage INSERTs into TimescaleDB for higher per-consumer throughput (target 500–1000 rows per INSERT batch rather than single-row inserts)
TimescaleDB I/O saturation visible in disk throughput metrics during specific consumer lag drain periods; chunk decompression operations appearing in TimescaleDB logs (decompress_chunk); write latency spiking for historical time ranges (not current time chunk); device backlog replay operations (devices offline >1 hour) correlating with I/O spikes
Threshold
Tier 3: Late-Arriving Data Chunk Decompression Cascade
Likely Bottleneck
Compressed chunk decompression triggered by late-arriving device data; at high device count, simultaneous decompression of many chunks saturates I/O
Recommended Evolution
Implement a late-data ingest path separate from the real-time ingest path: late data (> 2 hours old by device timestamp) routes to a dedicated consumer that writes to a separate TimescaleDB hypertable with relaxed compression policy; this isolates late-data decompression I/O from the real-time write path; add monitoring alert when device timestamp delta vs. wall clock > 2 hours
Redis memory utilization > 80%; Redis INFO keyspace showing active device key count significantly exceeding expected active fleet size; Redis eviction rate positive (LRU evictions occurring on device state keys); last-known-value read miss rate rising; alerting system false-positives from missing device state
Threshold
Tier 4: Cardinality Explosion and Redis Memory Saturation
Likely Bottleneck
Redis key space growing unboundedly as devices are added without corresponding key expiry; inactive/retired devices retaining Redis keys indefinitely
Recommended Evolution
Enforce TTL on all device state Redis keys (set TTL = max expected device reporting interval * 3, e.g., for 60s devices: TTL = 180s); implement a device lifecycle event in Kafka (device_decommissioned) that explicitly deletes Redis keys; shard Redis by device_id hash range across cluster nodes if memory requirement after TTL enforcement still exceeds single-node capacity
TimescaleDB write latency p99 > 50ms for batch INSERT operations; pg_stat_activity showing wait events on WAL flush; TimescaleDB active chunk autovacuum running continuously; Kafka consumer group lag for storage writers growing steadily at baseline (non-storm) load
Threshold
Escalation trigger: TimescaleDB single-node write throughput ceiling (~50k–100k rows/second depending on row width and chunk size configuration)
Likely Bottleneck
Tier 1: TimescaleDB Write Throughput Ceiling
Recommended Evolution
Monitor: error_rate, p95_latency_ms, queue_depth
Kafka consumer group lag jumping from baseline (<100k) to >10M messages within minutes; Kafka broker disk write rate elevated; TimescaleDB write thread pool fully saturated; Redis last-known-value update latency acceptable but historical storage significantly behind real-time; device reconnect event visible in device authentication logs correlating with lag spike
Threshold
Escalation trigger: Kafka consumer pool sized for steady-state throughput, not burst from device reconnect storm; insufficient storage writer parallelism for burst absorption
Likely Bottleneck
Tier 2: Kafka Consumer Lag from Reconnect Storm
Recommended Evolution
Monitor: error_rate, p95_latency_ms, queue_depth
TimescaleDB I/O saturation visible in disk throughput metrics during specific consumer lag drain periods; chunk decompression operations appearing in TimescaleDB logs (decompress_chunk); write latency spiking for historical time ranges (not current time chunk); device backlog replay operations (devices offline >1 hour) correlating with I/O spikes
Threshold
Escalation trigger: Compressed chunk decompression triggered by late-arriving device data; at high device count, simultaneous decompression of many chunks saturates I/O
Likely Bottleneck
Tier 3: Late-Arriving Data Chunk Decompression Cascade
Recommended Evolution
Monitor: error_rate, p95_latency_ms, queue_depth
Redis memory utilization > 80%; Redis INFO keyspace showing active device key count significantly exceeding expected active fleet size; Redis eviction rate positive (LRU evictions occurring on device state keys); last-known-value read miss rate rising; alerting system false-positives from missing device state
Threshold
Escalation trigger: Redis key space growing unboundedly as devices are added without corresponding key expiry; inactive/retired devices retaining Redis keys indefinitely
Likely Bottleneck
Tier 4: Cardinality Explosion and Redis Memory Saturation
Recommended Evolution
Monitor: error_rate, p95_latency_ms, queue_depth
Migration Readiness
12Migration Stages
3Direct device writes to PostgreSQL with time-range partitioning → Kafka ingestion buffer + TimescaleDB consumer writers
infoMigration trigger: PostgreSQL write p99 > 100ms at sustained device fleet load; device write errors spiking during reconnect events (devices cannot block on write failure); time-range partition pruning queries slow due to too many manual partitions; need for native rollup views without manual aggregation jobs
TimescaleDB as sole query layer for both real-time and historical queries → Redis last-known-value cache for real-time queries + TimescaleDB for historical queries
infoMigration trigger: Alerting system query latency > 500ms due to TimescaleDB query execution on current time chunk under write pressure; alert evaluation falling behind schedule; real-time dashboard queries competing with batch analytics queries on same TimescaleDB instance
TimescaleDB for both ingest storage and analytics queries → TimescaleDB for hot storage + ClickHouse for fleet analytics
infoMigration trigger: Multi-device aggregate queries (fleet-wide max/min/avg over 30-day windows) consuming > 30% of TimescaleDB CPU; analytics query p99 > 10s; analytics users and device ingest writers competing for I/O on the same TimescaleDB node; product requirement for fleet-wide queries that require full column scans
Risks
9Kafka introduces an ingestion buffer that makes device data
warningKafka introduces an ingestion buffer that makes device data available in storage with 1–5 second lag; real-time alerting systems reading from TimescaleDB must tolerate this latency or migrate to Redis last-known-value reads
TimescaleDB continuous aggregate refresh policy must be conf
warningTimescaleDB continuous aggregate refresh policy must be configured before production use; unconfigured refresh means rollup views are never updated
Redis last-known-value may lag TimescaleDB by up to Kafka co
warningRedis last-known-value may lag TimescaleDB by up to Kafka consumer latency (1–5s); alerting systems must tolerate this latency window and must not treat a stale Redis value as ground truth for historical analysis
Redis key schema for device state must be defined once and t
warningRedis key schema for device state must be defined once and treated as a contract; changes to the schema require coordinated deploy of both the Kafka consumer (writer) and alerting system (reader)
ClickHouse replication pipeline from TimescaleDB adds operat
warningClickHouse replication pipeline from TimescaleDB adds operational overhead; pipeline failures mean ClickHouse data is stale, and analytics users may not notice without explicit staleness indicators
ClickHouse query semantics differ from PostgreSQL/TimescaleD
warningClickHouse query semantics differ from PostgreSQL/TimescaleDB; analytics queries written for TimescaleDB may require rewrite to use ClickHouse-native functions
Projection lag creates a read-after-write window where users
criticalProjection lag creates a read-after-write window where users see stale data after their own writes. Mitigation: Route immediate post-write reads to the write store (session-scoped write token); accept eventual consistency only for non-user-initiated reads
↗ direct-db-to-cqrs
Projection rebuild after schema change can take hours or day
criticalProjection rebuild after schema change can take hours or days on large datasets. Mitigation: Design blue/green projection deployment: build new projection in parallel before switching traffic; test rebuild time in staging
↗ direct-db-to-cqrs
Cross-service workflows that previously used database transa
criticalCross-service workflows that previously used database transactions now require Saga orchestration. Mitigation: Design idempotent event handlers; implement compensating transactions for every multi-step workflow; test failure injection in staging
↗ modular-monolith-to-event-driven
Review Sections
6Referenced Intelligence