Chapter 12 · Time Series and Geospatial Workloads

Model Metrics/Telemetry and Location Data with Bounded Cardinality and Retention

Design telemetry and location schemas that bound key, label, member, and retention cardinality before operational cost becomes the failure mode.

Advanced180–220 minutesTelemetry/location modelingRedis Open Source 8.10.1Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart is ready to move from toy sensor and courier keys to thousands of devices. At this point the hardest failure mode is no longer command syntax: it is uncontrolled series count, label cardinality, location-member growth, retention, and hot-key concentration.

01

Estimate series cardinality from stable dimensions before creating keys.

02

Separate low-cardinality indexed labels from high-cardinality identities embedded in key names or application state.

03

Use raw/rollup retention tiers without claiming wall-clock deletion guarantees.

04

Model current location separately from historical location events.

05

Build an evidence sheet for memory, selectivity, write rate, query width, and p50/p95/p99 latency.

Exact lab baseline

All Chapter 12 mandatory labs reuse the disposable Chapter 01 environment: Redis Open Source 8.10.1 from Docker Official Image redis:8.10.1, container atlasmart-redis-ch01, standalone topology, host publication 127.0.0.1:6379, TLS disabled only because traffic stays on loopback, default ACL user disabled, named users atlasmart-app and academy-admin, logical database 0, AOF with appendfsync everysec plus RDB snapshots, persistent /data, and no explicit maxmemory limit or eviction policy. Redis 8 integrates Time Series into Redis Open Source; geospatial commands are core Redis commands. Fixtures stay under atlasmart:ch12:*. Mandatory work is local and uses synthetic telemetry/coordinates only; no paid service, production endpoint, or real credential is required.

1. Cardinality is multiplication, not a vague “lots of metrics” problem

If AtlasMart stores 20 sites × 4 zones × 500 sensors × 6 metrics, the upper bound is 240,000 time-series keys before replicas, rollups, or environments. Adding a label with 10 million request IDs does not merely add text—it changes metadata-index scale and query selectivity.

Dimension Good role Risk
site Bounded label Small controlled vocabulary
zone Bounded label Useful aggregation grouping
metric Bounded label Core query dimension
sensor ID Usually key identity; optional label only when needed High but stable cardinality
request/session/trace ID Do not make TS label by default Unbounded metadata cardinality
tenant Use key/ACL boundary plus bounded label for query convenience Label alone is not security isolation

2. Use a key schema that carries stable identity and bounded labels for query dimensions

A practical pattern is atlasmart:ch12:telemetry:{tenant}:site:metric:sensor, with labels repeating only the dimensions you actually query across. Duplication between key text and labels is sometimes intentional: keys support ACL/routing/debugging while labels support Time Series selection.

redis-cli · create three bounded example series
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:telemetry:atlasmart:baku-01:temperature:s01 RETENTION 86400000 LABELS tenant atlasmart site baku-01 zone cold-a metric temperature unit Cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:telemetry:atlasmart:baku-01:temperature:s02 RETENTION 86400000 LABELS tenant atlasmart site baku-01 zone cold-a metric temperature unit Cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:telemetry:atlasmart:baku-01:humidity:s01 RETENTION 86400000 LABELS tenant atlasmart site baku-01 zone cold-a metric humidity unit pctdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.QUERYINDEX tenant=atlasmart site=baku-01

The lab horizon is illustrative, not a production recommendation. Choose retention from audit/investigation/business requirements and measured cost.

3. Wrong approach: put unique request IDs into labels

A telemetry pipeline adds request_id as a label because “labels make filtering easy.” Every series now has effectively unique metadata, and the label index becomes less reusable and more expensive.

redis-cli · controlled high-cardinality smell
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:badlabel:1 RETENTION 60000 LABELS tenant atlasmart metric temperature request_id req-000001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:badlabel:2 RETENTION 60000 LABELS tenant atlasmart metric temperature request_id req-000002docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.QUERYINDEX request_id=req-000001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:badlabel:1

Two keys do not prove a memory crisis; they prove the modeling direction. The repair is to keep request/trace IDs in a logging/event system or Stream payload, and reserve Time Series labels for bounded dimensions that provide meaningful selection/grouping.

4. Retention tiering: raw detail and derived summaries answer different horizons

Tier Example purpose Design question
Raw telemetry Incident/debug horizon How long must individual samples remain queryable?
1-minute rollup Dashboard/operations Which reducers preserve the operational signal?
Hourly/daily rollup Long-term planning What precision is acceptable and what rebuild path exists?
Archive outside Redis Compliance/cold analytics Does Redis need to hold this horizon at all?

Do not use Time Series retention as an exact legal erasure clock. It is driven by reported timestamps and subsequent writes. If a privacy/compliance workflow requires deletion by a deadline, use explicit data-management controls and verify final state.

5. Current GEO state and historical location need separate cardinality plans

For 50,000 active couriers, one GEO member per courier is 50,000 current positions—not every position ever reported. Historical location samples should be written to a time-series/stream model with bounded retention. Reusing a courier member name updates current location and naturally bounds GEO member cardinality to active entities.

redis-cli · current position projection plus historical sample
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:couriers:atlasmart 49.8671 40.4093 courier-42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:location-history:atlasmart:courier-42:lon RETENTION 3600000 LABELS tenant atlasmart entity courier-42 axis londocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:location-history:atlasmart:courier-42:lat RETENTION 3600000 LABELS tenant atlasmart entity courier-42 axis latdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MADD atlasmart:ch12:location-history:atlasmart:courier-42:lon 1700000000000 49.8671 atlasmart:ch12:location-history:atlasmart:courier-42:lat 1700000000000 40.4093docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch12:geo:couriers:atlasmart

Two separate numeric series are simple for teaching but can create many keys. In production, evaluate whether a Stream/event document, external telemetry store, or application encoding fits multi-dimensional location history better.

6. Memory budget must include more than sample payloads

A capacity sheet should include key names, Time Series metadata/labels, chunks, compaction destinations, GEO sorted sets, client/output buffers, persistence/replication buffers, allocator fragmentation, and fork headroom. maxmemory is not process RSS and is not configured in this lab.

redis-cli · collect current memory evidence
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO memorydocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:telemetry:atlasmart:baku-01:temperature:s01docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:telemetry:atlasmart:baku-01:temperature:s02docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:geo:couriers:atlasmartdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:telemetry:atlasmart:baku-01:temperature:s01

Record the exact server build and dataset shape beside every byte count. Memory measurements on three tiny keys are a method demonstration, not a production sizing result.

7. Query selectivity is a first-class metric

redis-cli · compare narrow and broad selectors
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.QUERYINDEX tenant=atlasmart site=baku-01 metric=temperaturedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.QUERYINDEX tenant=atlasmartdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MRANGE - + COUNT 2 FILTER tenant=atlasmart site=baku-01 metric=temperature

Track “series matched” before “samples returned.” A narrow time window can still be expensive if the label predicate selects hundreds of thousands of series. Conversely, one hot series with an enormous range can be expensive even with perfect metadata selectivity.

8. Measure latency distributions without fabricating benchmark numbers

The academy does not have a Redis runtime in this generation environment, so Chapter 12 does not publish invented p50/p95/p99 values. The lab records server-side command latency statistics after you run representative workloads.

redis-cli · server-side latency/command evidence
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO commandstatsdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO latencystatsdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin LATENCY DOCTOR

For production acceptance, pair server metrics with client end-to-end histograms and record payload size, concurrency, pipeline depth, network placement, persistence settings, and CPU/memory pressure. Tail latency is workload-specific.

9. Hot keys can dominate otherwise acceptable cardinality

A single global GEO set receiving every courier update or one global telemetry series receiving every tenant event can concentrate CPU and network load. Partitioning can help, but only when the query contract survives partitioning. A city/tenant partition that forces fan-out across every shard may merely move cost.

Cluster preview

Redis Cluster uses 16,384 hash slots and multi-key operations have slot-locality constraints. Chapter 21 covers routing/resharding in depth. For now, include hash-tag/key-placement assumptions in every design review rather than assuming standalone behavior scales unchanged.

10. Failure injection: retention and location staleness are different failure modes

If telemetry producers stop, retention may stop advancing because no new timestamps arrive; “old” samples do not disappear merely because wall-clock time passes. If location producers stop, the GEO member can remain indefinitely as a stale current position unless the application also tracks freshness. Model freshness explicitly.

redis-cli · separate current position from freshness timestamp
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:couriers:atlasmart 49.8750 40.4150 courier-42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SET atlasmart:ch12:geo-freshness:atlasmart:courier-42 1700000060000 EX 300docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOPOS atlasmart:ch12:geo:couriers:atlasmart courier-42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GET atlasmart:ch12:geo-freshness:atlasmart:courier-42

The TTL key is illustrative freshness metadata. If it expires, the GEO member still exists; the application must remove or ignore stale location entries according to policy. Do not mistake a side freshness key for atomic coupling.

11. Cleanup

redis-cli · bounded Chapter 12 cleanup
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin UNLINK atlasmart:ch12:telemetry:atlasmart:baku-01:temperature:s01 atlasmart:ch12:telemetry:atlasmart:baku-01:temperature:s02 atlasmart:ch12:telemetry:atlasmart:baku-01:humidity:s01 atlasmart:ch12:badlabel:1 atlasmart:ch12:badlabel:2 atlasmart:ch12:geo:couriers:atlasmart atlasmart:ch12:location-history:atlasmart:courier-42:lon atlasmart:ch12:location-history:atlasmart:courier-42:lat atlasmart:ch12:geo-freshness:atlasmart:courier-42

UNLINK targets only the named Chapter 12 fixtures. Do not replace this with FLUSHDB, FLUSHALL, or broad pattern deletion on a shared Redis instance.

12. Production judgment

A robust telemetry/location model has explicit formulas for key count, label cardinality, samples per second, bytes/sample measured on representative data, retention tiers, derived-series multiplier, active GEO members, update frequency, query selectivity, and failure freshness. It documents AOF/replication headroom, Cluster slot strategy, ACL/TLS boundaries, retry/idempotency rules, deletion/privacy workflows, and rollback/rebuild plans. Avoid universal thresholds such as “one million series is fine”; benchmark your topology and budget.

Check your understanding

  1. Why is series count often multiplicative?
  2. Why is request_id usually a bad Time Series label?
  3. Why does a GEO member update help bound current-state cardinality?
  4. Can retention remove stale GEO members?
  5. What should p99 latency be compared with?
Review the answers

Each combination of identity dimensions and metrics can create a separate key, so stable dimensions multiply.

It has very high/unbounded cardinality and rarely creates reusable query groups.

The same member name replaces its coordinate instead of appending another member.

No. Time Series retention applies to Time Series samples; GEO freshness/removal needs separate policy.

A workload-specific service-level objective measured under representative payload, concurrency, network, persistence, and resource pressure—not a universal number.

13. Summary and next step

You now have a capacity-aware model for Time Series and GEO rather than a command demo. Lesson 5 composes these structures with Streams, Search, and application-side processing while preserving data lineage, authorization, retries, and consistency boundaries.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.