Chapter 12 · Time Series and Geospatial Workloads
Time-Series Keys, Labels, Retention, Duplicate Policies, and Compression Concepts
Model one AtlasMart sensor metric as an explicit Redis time series and prove timestamp, label, retention, duplicate, compression, persistence, and memory behavior.
Learning outcomes
AtlasMart has cold-chain sensors that emit temperature readings every few seconds. A plain string can hold the latest value, but operations needs a timestamped history, bounded retention, metadata labels, duplicate-timestamp rules, and evidence of storage cost.
Model one metric as a time-series key containing timestamp/value samples.
Use labels for bounded metadata without confusing labels with ACL or tenant isolation.
Explain retention as sample age relative to the highest reported timestamp—not wall-clock key TTL.
Choose and test duplicate policies instead of silently overwriting same-timestamp samples.
Measure TS.INFO and MEMORY USAGE evidence while treating chunk/compression details as version-sensitive implementation context.
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. Mental model: key → ordered samples, not key → one scalar
A Redis time-series key stores an ordered sequence of
samples. Each sample is a pair: an integer Unix
timestamp in milliseconds and a numeric value.
The timestamp is event time supplied by the client or generated
by Redis when * is used. The value is a
double-precision number. Labels are string name/value metadata
attached to the series itself, not to each sample.
| Concept | Meaning | AtlasMart example |
|---|---|---|
| Series key | Identity of one metric stream |
atlasmart:ch12:ts:temperature:baku-01:s01
|
| Sample | Timestamp + numeric value | 1700000000000 → 4.2 |
| Label | Series-level indexed metadata |
site=baku-01, metric=temperature
|
| Retention | Maximum sample age relative to highest reported timestamp |
300000 ms = five-minute synthetic lab horizon
|
| Duplicate policy | What to do when timestamp already exists |
BLOCK, LAST, MIN,
MAX, SUM, FIRST
|
Event timestamp is part of the sample. Client ingest time is when the request reaches Redis. Wall-clock time on your laptop is neither of those unless your application deliberately makes them equal. A seconds-versus-milliseconds bug shifts event time by a factor of 1000.
2. Preflight the actual Redis 8.10.1 command surface
Before teaching a historically module-based capability, prove the target server exposes it. Redis 8 integrates Time Series into Redis Open Source, but clients and managed services can still lag or expose different policy boundaries.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO serverdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO TS.CREATE TS.ADD TS.INFO TS.RANGE TS.ALTER TS.DELdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin ACL DRYRUN atlasmart-app TS.ADD atlasmart:ch12:ts:test 1 1docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO persistencedocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO memory
Expected evidence: server version reports 8.10.1;
Time Series commands are known; the disposable application ACL
either permits the intended key/command or returns a concrete
ACL denial that must be repaired deliberately.
INFO persistence proves AOF/RDB configuration, not
that every accepted sample has already reached durable storage.
3. Create one bounded, labeled, compressed series
The smallest useful AtlasMart model is one key per stable sensor+metric identity. The lab uses low-cardinality labels that support multi-series queries later.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:ts:temperature:baku-01:s01 RETENTION 300000 ENCODING COMPRESSED DUPLICATE_POLICY BLOCK LABELS tenant atlasmart site baku-01 zone cold-a metric temperature sensor s01 unit Cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:ts:temperature:baku-01:s01docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:ts:temperature:baku-01:s01
TS.INFO should expose fields such as total samples,
first/last timestamp, retention, chunk metadata, duplicate
policy, labels, source/rules, and memory usage. Exact byte
counts and chunk layout are allocator/version dependent; record
them, but do not turn them into a cross-version constant.
4. Add deterministic samples and prove ordering
Explicit timestamps make the lesson reproducible and expose unit mistakes. Redis orders the series by timestamp, not by network arrival order.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:temperature:baku-01:s01 1700000000000 4.2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:temperature:baku-01:s01 1700000060000 4.4docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:temperature:baku-01:s01 1700000030000 4.3docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:ts:temperature:baku-01:s01 - +docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:ts:temperature:baku-01:s01
The range result is timestamp ordered even though the third request arrives after a later timestamp. An out-of-order sample can still be rejected if it falls outside the retention window; “Redis accepts out of order” is not the same as “Redis accepts arbitrary history forever.”
5. Wrong approach: seconds in a milliseconds field
A producer accidentally sends 1700000060 (seconds)
beside millisecond timestamps around 1700000000000.
The number is syntactically valid, so type checking alone cannot
save you.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:temperature:baku-01:s01 1700000060 99.9docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:ts:temperature:baku-01:s01 - +docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.DEL atlasmart:ch12:ts:temperature:baku-01:s01 1700000060 1700000060docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:ts:temperature:baku-01:s01 - +
Depending on the already-advanced retention boundary, the bad old timestamp may be rejected as too old; on an unbounded series it could be accepted and land decades away from the intended event time. The repair is application-side timestamp validation plus a bounded retention policy—not hoping Redis infers units.
6. Duplicate timestamps are a business rule, not a parser detail
Two measurements at exactly the same millisecond can mean retry, correction, concurrent instruments, or aggregation. Redis therefore makes the policy explicit.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:temperature:baku-01:s01 1700000060000 8.8docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:temperature:baku-01:s01 1700000060000 4.5 ON_DUPLICATE LASTdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:ts:temperature:baku-01:s01 1700000060000 1700000060000docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ALTER atlasmart:ch12:ts:temperature:baku-01:s01 DUPLICATE_POLICY MAXdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:temperature:baku-01:s01 1700000060000 4.1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:ts:temperature:baku-01:s01 1700000060000 1700000060000
The first duplicate should fail under BLOCK.
ON_DUPLICATE LAST is a per-write override. After
DUPLICATE_POLICY MAX, a lower retry should not
replace the existing higher value. Choose a policy from event
semantics; never use SUM for retries unless
duplicate arrival truly means additive business quantity.
7. Retention advances with reported timestamps—not a wall-clock scheduler
Redis Time Series retention differs from key expiration. A retention value is a maximum sample age relative to the series’ highest reported timestamp, and expiration is driven by subsequent Time Series writes. Sleeping for five minutes is not the mechanism.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:ts:retention-demo RETENTION 1000 DUPLICATE_POLICY BLOCK LABELS tenant atlasmart purpose retention-demodocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:retention-demo 1000 1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:retention-demo 1500 2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:retention-demo 2501 3docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:ts:retention-demo - +docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.ADD atlasmart:ch12:ts:retention-demo 1200 9
After the highest timestamp advances to 2501, timestamps older
than its retention horizon are no longer eligible as fresh
historical inserts, and old retained data is cleaned according
to Time Series retention/chunk behavior. Do not promise
deletion at a wall-clock instant or use retention as a privacy
erasure SLA; verify actual TS.RANGE/TS.INFO
state and use explicit deletion workflows where a hard erasure
deadline exists.
8. Compression is an implementation/storage choice, not lossy metric compression
ENCODING COMPRESSED changes how chunks are stored;
it does not intentionally approximate numeric values the way a
probabilistic sketch does. UNCOMPRESSED can trade
memory for different CPU/write characteristics. Measure on
representative data rather than assuming one is universally
faster.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:ts:compressed ENCODING COMPRESSED LABELS tenant atlasmart metric demodocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:ts:uncompressed ENCODING UNCOMPRESSED LABELS tenant atlasmart metric demodocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MADD atlasmart:ch12:ts:compressed 1 10 atlasmart:ch12:ts:uncompressed 1 10 atlasmart:ch12:ts:compressed 2 11 atlasmart:ch12:ts:uncompressed 2 11 atlasmart:ch12:ts:compressed 3 12 atlasmart:ch12:ts:uncompressed 3 12docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:ts:compresseddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:ts:uncompresseddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:ts:compresseddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:ts:uncompressed
A three-sample fixture is too small to choose a production encoding. It exists to prove the configuration and measurement method; benchmark representative cardinality and value/timestamp patterns before deciding.
9. Labels improve discovery but can create metadata cardinality
Labels support indexed multi-series selection. Stable dimensions such as site, zone, metric, and unit are usually useful. Request IDs, trace IDs, user IDs, or random session values can make the label index itself a high-cardinality workload.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.QUERYINDEX tenant=atlasmart metric=temperaturedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.QUERYINDEX tenant=atlasmart site=baku-01
Labels are query metadata, not access control. An ACL that
permits a broad key pattern can still expose another tenant’s
series even if a query includes tenant=atlasmart.
Security boundaries belong in key patterns, users/roles,
network/TLS, and application authorization.
10. Persistence, replication, and durability boundaries
Time-series samples participate in Redis persistence and
replication like other Redis data. With AOF
everysec, an acknowledged write is not equivalent
to synchronous durable storage. Replication is asynchronous and
does not turn a replica into a backup. Later chapters cover
these mechanisms in depth.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO persistencedocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO replicationdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin BGSAVEdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO persistence
The evidence proves configured/current persistence state only. A backup is not complete until a separate copy is restored and validated.
11. Reproducible cleanup
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin UNLINK atlasmart:ch12:ts:temperature:baku-01:s01 atlasmart:ch12:ts:retention-demo atlasmart:ch12:ts:compressed atlasmart:ch12:ts:uncompressed
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
Use Redis Time Series when the workload benefits from timestamp-ordered numeric samples, bounded retention, label-driven selection, server-side bucket aggregation, and low-latency access. Do not use it merely because data “has a timestamp.” Consider expected samples/second, series count, label cardinality, chunk memory, retention horizon, compaction fan-out, replication/AOF overhead, query width, and client timeout/retry behavior. A retry with the same timestamp is only safe when the duplicate policy matches the business event model. In Cluster, key placement and multi-key query behavior must be validated rather than inferred from standalone labs. Managed-service limits and client support are version/platform dependent.
Check your understanding
- Why is Time Series retention not equivalent to EXPIRE on the key?
- What does a label protect?
- Why can a duplicate timestamp not have one universally correct policy?
- Does COMPRESSED mean lossy approximate values?
- What should be recorded before comparing memory?
Review the answers
It ages samples relative to the highest reported timestamp and is advanced by Time Series writes; it is not a wall-clock key deletion timer.
Nothing by itself. Labels aid discovery/filtering; ACL/network/application authorization provide security boundaries.
The right behavior depends on whether the event is a retry, correction, min/max observation, or genuinely additive quantity.
No. It is a storage encoding choice, not probabilistic approximation.
Server version, encoding/chunk settings, sample count/pattern, labels, allocator/environment, persistence/topology, and the exact MEMORY/TS.INFO evidence.
13. Summary and next step
You now have a precise source-series model: ordered millisecond samples, bounded labels, retention semantics, explicit duplicates, observable compression/memory, and durability caveats. Lesson 2 builds aggregation buckets, downsampling rules, and multi-series queries on top of this source state without confusing derived summaries with raw truth.