ML Systems Lab Open interactive version →
Intermediate 29 min read feature storeMLOpsarchitecturefeature serving

Feature Store Architecture

Offline store, online store, registry, materialisation, latency SLAs

Five ML teams at one company all need the same thing: "user average spend in last 30 days." Each team builds its own pipeline. Five nightly SQL jobs. Five Redis keys. Five different implementations of the 30-day window, each with its own null handling, timezone quirks, and new-user edge cases. A user spends ten thousand dollars at midnight, and each team's copy of the feature updates at a slightly different time with a slightly different number. The fraud model and the recommendation model now disagree about this user's spending. Neither team can see the other's value. Neither is wrong by its own logic. Yet they are quietly inconsistent, and both models suffer for it.

A feature store fixes this by computing each feature *once,* correctly, and serving that one answer to everyone — through two storage backends built for two very different jobs.


The offline store: history, for building training sets

It keeps every past value of a feature, stamped with time. That is what lets you ask, "What was this user's 30-day average spend *as of* time T?" — the point-in-time query that prevents leakage. Without it, your training pipeline reaches for *today's* values when building rows for last month's events, and every rolling aggregate silently swallows data that didn't exist yet when the prediction would have been made.


The online store: the current value, fast

A live fraud request needs this user's spend average in under 5ms. The online store (Redis, DynamoDB, Cassandra) holds only the *latest* value per user and returns it at memory speed. No history — that's the offline store's job. It's sized for latency at peak traffic, not for storage.

Online-store latency failure modes. The online store's P50 latency can look fine while P99 spikes badly, and the usual causes are specific, not vague "network blips": a hot key (one popular entity — a viral post, a high-volume account — absorbing a disproportionate share of reads, so requests queue up behind it), memory pressure that forces the store to evict cached keys under load, or an oversized serialized feature vector that's slow to deserialize on every read. The fixes track the causes directly: hash or shard hot keys so no single partition takes outsized traffic, add capacity so eviction pressure eases, and put a circuit breaker in front of the store so a P99 spike degrades gracefully instead of cascading into the caller.


The registry and materialization: the parts a plain database lacks

The *registry* is the governance layer: it records each feature's definition, owner, freshness SLA, upstream dependencies, and which models consume it — so teams can find what already exists and know what breaks if a pipeline is retired. *Materialization* is the act of computing features from raw data and writing them to both stores: batch (Spark, Airflow, hourly/daily) when some staleness is fine, or streaming (Kafka → Flink → Redis) when 5-minute freshness matters, like fraud or live inventory. Each write to the online store is typically stamped with a TTL a little longer than the materialization interval -- insurance against a value going stale forever if a job stalls. But that insurance has a sharp edge: if materialization stops for good (a pipeline decommissioned, a job silently failing) the online store keeps serving its last computed value as if nothing were wrong, right up until that TTL lapses -- then the key vanishes and a lookup returns null. Serving code almost always treats a missing key as "impute the default," not "raise an error," so the model quietly starts scoring on a placeholder value with no exception anywhere in the stack. No error in the logs is not evidence a feature pipeline is healthy -- only an explicit freshness check is.

And that's the real answer to "isn't this just a database?" A database stores bytes. A feature store adds four things a database won't: point-in-time-correct history, one shared computation path across online and offline, a registry for discovery and lineage, and materialization with freshness monitoring. With all four, training-serving consistency becomes a property of the *system* — not a hope resting on individual engineers remembering to match each other.

Key points

Takeaway

A feature store is not storage — it is the infrastructure that makes training-serving consistency a structural property rather than an agreement between engineers who will eventually disagree.

Recap

Check your understanding

Q1. A data scientist wants to reuse "user_30d_purchase_count" computed by another team. Select the two things the feature store provides that make this safe.

Q2. Your online store (Redis) is serving a feature at 3ms P50 but 800ms P99. What is causing this and how do you fix it?

Q3. Describe the materialisation pipeline for a feature "user_last_7d_app_opens" that needs to be available in the online store with <5 minute staleness.

Q4. A feature was deprecated 3 months ago but a model in production still uses it. The feature computation pipeline was shut down. What is the failure mode and how do you prevent it?

Try it interactively

ML Systems Lab is a free interview-prep platform for ML engineers — work through the full interactive module, quizzes, and drills.

Open ML Systems Lab →