ML Feature Pipelines and Feature Stores Questions
Data infrastructure for machine learning: feature pipelines, feature stores, online/offline consistency, training-serving skew, and data preparation for models. Covers building reliable feature platforms and preventing leakage in the data path feeding models. The data-engineering-for-ML topic.
Design a low-latency online feature retrieval API for model inference. Specify the API contract (request and response shape), authentication and authorization approach, caching strategy, timeout and retry semantics, and how you would include feature versioning and metadata in the response so a client can detect staleness.
Sample Answer
Direct answer: The API contract for online feature retrieval needs to specify entity IDs and requested feature names in, values and per-feature staleness metadata out, with authentication scoped per caller, a short client-side timeout with a defined retry policy, and response-embedded versioning so a caller can detect when it received a stale or mismatched feature definition.
Structured elaboration:
- Request/response contract. Request: entity ID(s) (support batch lookups since most inference paths need many features at once), a list of feature names or a named feature group/vector, and an optional as-of timestamp for offline/backtesting parity. Response: a map of feature name to value, plus per-feature metadata (last-computed timestamp, feature definition version) so the caller can decide whether a feature is too stale to use.
- Authentication and authorization. Service-to-service auth via short-lived tokens (mTLS or a token issued by a service-identity system) rather than static API keys; authorization scoped per feature group so a caller only sees features it is entitled to (relevant for PII (personally identifiable information)-sensitive features).
- Caching strategy. The API itself should be cache-friendly: deterministic request shape, and response headers or fields that state a TTL (time-to-live) so a client-side cache (or CDN-style edge cache for less dynamic features) knows how long it may reuse a value.
- Timeout and retry semantics. A tight client-side timeout (a few milliseconds under the overall inference budget) with at most one retry to a different replica, not a retry storm; on timeout, the client contract should specify a documented fallback (return a default/null feature with a flag, rather than blocking the whole inference request).
- Feature versioning and metadata in the response. Include the feature definition's version or hash in the response so a caller doing an online/offline consistency check can confirm the online value was produced by the same transformation logic as the training data.
Worked example: A request for {"entity_id": "u_123", "features": ["f_recency_7d", "f_avg_spend_30d"]} returns {"f_recency_7d": {"value": 3.2, "computed_at": "2026-07-23T10:15:02Z", "version": "v3"}, "f_avg_spend_30d": {"value": null, "computed_at": null, "version": "v3", "status": "missing"}}; the caller's contract with the platform says a missing feature is returned explicitly as null with a status field rather than the whole request failing, so a single missing feature does not take down inference for the entity.
Trade-offs & pitfalls: Returning rich per-feature metadata on every response adds payload size and marshaling cost at high QPS (queries per second); a common mitigation is to make metadata optional via a request flag, so hot-path inference can skip it and only debugging/monitoring calls request it. A retry policy that is too aggressive (multiple retries with no backoff) can turn a single slow shard into a cascading overload; the contract should specify a hard retry budget and prefer failing fast with a fallback over retrying into an already-struggling backend. Embedding a feature-definition version in every response is easy to forget to check on the consumer side, so the value it provides (catching a schema mismatch) only materializes if the platform also builds tooling that actively surfaces version mismatches rather than leaving it to each consumer to remember to compare.
Design a feature store that must sustain 100,000 feature writes per second while keeping average online read latency under 50ms. Outline the architecture layers (ingestion, transformation, offline store, online store, materialization jobs), the partitioning strategy, and the online storage technology choice, with emphasis on the write path.
Sample Answer
Direct answer: Sustaining 100,000 writes per second while keeping reads under 50ms means the write path and read path need to be architecturally separated: an ingestion and transformation layer absorbs the write volume and batches it efficiently into the offline store, while materialization jobs push a summarized, read-optimized copy into the online store on a cadence the read SLA (service-level agreement) can tolerate, rather than the online store taking every write synchronously.
Structured elaboration:
flowchart LR
Producers["Producers (100k writes/sec)"] --> Log["Kafka log"]
Log --> Xform["Transform layer"]
Xform --> Offline["Offline store (Parquet/Iceberg)"]
Xform --> Materialize["Materialization job"]
Materialize --> Online["Online store, 20 shards (DynamoDB / Cassandra)"]
Reader["Reads, under 50ms"] --> Online
- Ingestion layer. A message queue (Kafka or similar) absorbs the 100k writes/sec as an append-only log, decoupling producers from the rate the downstream stores can actually sustain and giving replay capability if a downstream consumer falls behind.
- Transformation layer. Stream or micro-batch processors (Flink/Spark Structured Streaming) consume the log, compute or pass through feature values, and write to both the offline store (for training, at full fidelity and volume) and a materialization pipeline feeding the online store.
- Offline store. Columnar, append-friendly storage (Parquet on object storage, or a table format like Iceberg/Delta) handles 100k writes/sec easily since it is optimized for high-throughput sequential writes, not point lookups.
- Online store and materialization. Rather than writing every one of the 100k events/sec directly into the low-latency online store, materialize periodically (e.g. every few seconds to a minute) into the online store's write path, or use an online store designed for high write throughput (a wide-column store like Cassandra, or a managed store like DynamoDB with provisioned write capacity) if genuinely every write must be reflected online quickly.
- Partitioning strategy. Partition by entity ID (consistent hashing) across enough shards on both the write and read side that no single partition absorbs a disproportionate share of the 100k writes/sec; monitor for and rebalance around emerging hot partitions.
- Online storage technology choice. DynamoDB or Cassandra are natural fits here because they are built for high sustained write throughput with horizontal scaling, unlike a single-node Redis instance which would need careful cluster sharding to sustain 100k writes/sec reliably.
Worked example: At 100k writes/sec, if you partition into 20 shards, each shard handles 5,000 writes/sec, which is comfortably within a single Cassandra or DynamoDB partition's sustained write capacity when the partition key is well-distributed (recall DynamoDB's roughly 1,000 WCU per-partition soft limit, so 5,000 writes/sec on one logical shard would actually need to be spread across at least 5 underlying partitions, reinforcing that partition-key design, not just shard count, determines whether the write path holds up).
Trade-offs & pitfalls: A store optimized for 100k writes/sec is not automatically also optimized for sub-50ms reads; the two workloads have different access patterns (append-heavy, roughly uniform writes vs. skewed, latency-sensitive reads), so the same store often needs different tuning (or a different store entirely) for each, which is why materializing into a separate, read-optimized online copy is the standard pattern rather than serving reads directly off the write-optimized store. Under-partitioning the write path is the single most common way this design fails in practice: a partition key that looks well-distributed in aggregate can still have local hot spots (a batch of correlated writes for related entities arriving together), so monitoring per-partition write rates, not just the aggregate, is necessary to catch it before it causes write throttling.
Design an online feature retrieval service to achieve median latency under 5ms at 100,000 requests per second. Cover data store choice, multi-region caching, cache warming, hotspot mitigation, consistency model, load balancing, handling high write throughput from upstream streaming jobs, and how you would measure and maintain tail latency.
Sample Answer
Direct answer: Hitting a 5ms median at 100k requests/sec means the design has to eliminate every unnecessary network hop and put the hot path entirely in memory close to the caller, with the data store itself sharded wide enough that no single shard is the bottleneck. The architecture layers, in order from the client: a local or co-located cache, a sharded low-latency store (Redis Cluster or a DynamoDB-style store), multi-region replicas, and an observability layer that separately tracks median and tail latency because at this scale they diverge.
Structured elaboration:
flowchart LR
Client["Inference client"] --> Region1["Regional read path"]
subgraph Region["Nearest region"]
Region1 --> LocalCache["Local cache"]
LocalCache -->|miss| Shard["Sharded online store (20 shards, 3x replicas)"]
end
Primary["Primary write path"] -->|async replication| Region
Primary -->|async replication| RegionB["Other regions"]
Shard -->|slow path fallback| Stale["Serve slightly stale cached value"]
- Data store and sharding. Partition the keyspace (typically by hashing entity ID) across enough shards that each shard handles a small fraction of 100k QPS (queries per second) with headroom, e.g. 20 shards at ~5k QPS each with 3x replication for read fan-out.
- Multi-region caching. Serve reads from the region closest to the caller. Each region holds a local read replica (or a fully local cache warmed from the primary) so a request never crosses a region boundary on the read path; cross-region replication happens asynchronously in the background.
- Cache warming. On a region failover or a cold cache, warming from a snapshot or from the primary region avoids a thundering herd of cache misses hitting the backing store simultaneously; a common pattern is to replay the last N minutes of writes into the new cache before routing traffic to it.
- Hotspot mitigation. A small number of keys will still dominate traffic (see the hot-key sub-area); mitigate with a local in-process cache for the hottest keys, request coalescing (collapse concurrent identical lookups into one backend call), and, if needed, replicating hot keys onto every shard rather than one.
- Consistency model. Accept eventual consistency between regions (bounded by replication lag, typically tens to low hundreds of milliseconds) in exchange for the latency win; document the staleness bound so consumers know what they are trading.
- Load balancing. Client-side or sidecar-based load balancing with health checks and fast failure detection, so a single slow shard does not drag down the aggregate tail.
- Measuring and maintaining tail latency. Track p50, p95, p99, and p99.9 separately, not just an average; instrument per-shard and per-region so you can find the shard causing the tail rather than only seeing the aggregate. Use load shedding or a fast timeout-plus-fallback (serve a slightly stale cached value) for the small percentage of requests that would otherwise blow the SLA (service-level agreement).
Worked example: At 100k QPS with a target median of 5ms, budget the latency: roughly 1-2ms for the network hop to a co-located cache, 0.5-1ms for the cache lookup itself, and the remainder as safety margin for queueing under load. If each shard node can sustain 8,000 ops/sec at that latency (a realistic number for an in-memory store with pipelining), you need at least ceil(100,000 / 8,000) = 13 shards for the primary write path, and you would typically round up to 16-20 to leave headroom for uneven key distribution and node maintenance.
Trade-offs & pitfalls: The most common mistake at this scale is designing for the median and being surprised by the tail: a 5ms median with a 200ms p99.9 still means thousands of slow requests per second at 100k QPS, which is often unacceptable for a synchronous inference path. A second common mistake is under-provisioning replica read fan-out, so a single popular shard saturates even though the aggregate cluster has spare capacity. Cross-region async replication means a model can read a feature that is a few hundred milliseconds stale right after a write; if the use case cannot tolerate that (for example, a fraud rule keyed on a just-written flag), the design needs a synchronous or quorum-read path for that specific feature instead of the default async replication.
Design a multi-tenant feature platform to support hundreds of teams and thousands of feature definitions. Cover tenant isolation (logical vs physical), resource quotas, cost attribution and chargeback, feature namespace and discovery, onboarding flow, and security (access control and audit logging).
Sample Answer
Direct answer: A multi-tenant feature platform for hundreds of teams needs tenant isolation so one team cannot starve or corrupt another's workload, resource quotas and cost attribution so usage maps back to accountability, a shared but namespaced catalog so features are discoverable without colliding, a low-friction onboarding path, and access control with audit logging baked in from the start rather than bolted on later.
Structured elaboration:
- Tenant isolation. Logical isolation (shared infrastructure, separate namespaces, quota-enforced) is cheaper to operate and scales to hundreds of teams more easily than physical isolation (dedicated clusters per tenant), but it requires strong quota enforcement so a noisy tenant cannot degrade others; physical isolation is reserved for tenants with hard compliance or extreme-scale requirements that justify the operational cost.
- Resource quotas. Per-tenant limits on storage, compute (materialization job concurrency), and read/write throughput against the online store, enforced at the platform layer (not just monitored after the fact), with headroom for legitimate bursts via a request-based override process.
- Cost attribution and chargeback. Tag every resource (storage bytes, compute-seconds, online-store operations) with a tenant ID at creation time, and aggregate into a per-team cost report; this is what makes quotas defensible and gives teams an incentive to clean up unused features.
- Feature namespace and discovery. A shared catalog with tenant-scoped namespaces (so
team_a.feature_xandteam_b.feature_xdo not collide) plus cross-tenant search and reuse, since a major value of a shared platform is avoiding duplicate feature engineering across teams. - Onboarding. Self-service registration with sane defaults (starter quotas, template pipelines) so a new team can start producing features within hours, not weeks of platform-team involvement, gated by automated checks (schema validation, basic hygiene) rather than manual review for every request.
- Security. Role-based access control scoped per namespace, with audit logging of who read, wrote, or materialized what, satisfying both internal governance and external compliance needs.
Worked example: With hundreds of teams and thousands of feature definitions, a realistic starting quota might be: 500GB offline storage, 10,000 online-store operations/sec, and 4 concurrent materialization job slots per team by default, with an escalation path (a lightweight request reviewed against actual usage data) for teams that outgrow the default; cost attribution then shows, for example, that 10% of teams consume 60% of platform resources, which becomes the input to a capacity-planning and chargeback conversation rather than an ad-hoc "why is the bill so high" investigation.
Trade-offs & pitfalls: Logical isolation's biggest failure mode is quota enforcement that is advisory rather than actually enforced at the resource layer (a team's job silently exceeds its quota and degrades others before anyone notices); the fix is hard limits with clear, fast-failing errors rather than soft alerts a team can ignore. Namespacing solves the naming-collision problem but does not by itself solve feature duplication (two teams independently building near-identical features under different names); that requires an active discovery and deduplication process on top of the namespace, not just the namespace itself. Over-indexing on self-service onboarding without automated hygiene checks (schema validation, basic testing) trades short-term onboarding speed for long-term platform-quality debt, since a platform with hundreds of self-onboarded teams and no guardrails accumulates low-quality, undocumented features quickly.
A fraud-scoring model requires retrieving 50 features per user in under 10ms at 10,000 queries per second. Propose a deployment and storage architecture (online store choice, replication, caching, network path) to meet this SLA, including capacity estimates and a fallback strategy for when the SLA cannot be met.
Sample Answer
Direct answer: Retrieving 50 features per user under 10ms at 10,000 QPS (queries per second) is a batch-lookup, capacity-planned design problem: one network round trip per request that fetches all 50 features together (never 50 separate calls), sized against a store that can sustain the resulting operation rate with headroom, plus an explicit fallback for the tail that would otherwise miss the SLA (service-level agreement).
Structured elaboration:
- Batch retrieval, not per-feature calls. Fetching 50 features one at a time at 10k QPS would mean 500k individual operations/sec and 50x the network round trips; instead, store the 50 features as a single serialized record (or a small number of grouped records) keyed by user ID, so one
GET(orMGETacross a small number of keys) returns everything needed. - Storage and replication. A Redis-based online store with 3x replication across a small number of shards easily sustains 10,000 GETs/sec with single-digit-millisecond latency; size shard count from measured per-node throughput with headroom (as in the earlier capacity-estimation examples in this topic).
- Network path. Co-locate the feature-serving tier with the store (same availability zone/rack where possible) to minimize round-trip time; avoid routing through an extra proxy hop on the hot path if it is not adding value.
- Capacity estimate. At 10k QPS with one batched call per request, that is 10k ops/sec against the store, comfortably within a single well-provisioned Redis Cluster's capacity (which handles well over 100k ops/sec); the binding constraint is more likely to be the payload size of 50 features per response and the serialization/deserialization CPU cost than raw op throughput.
- Fallback strategy. For the small percentage of requests that would exceed 10ms (a cold cache entry, a transient network blip), the contract should define a graceful degradation: serve a cached-but-slightly-stale value, serve a default/neutral value for the missing feature with a flag the model can act on, or in the worst case, skip scoring and route to a simpler fallback rule rather than blocking the transaction.
Worked example: If each of the 50 features is a small numeric or short categorical value averaging 20 bytes serialized, a per-request payload is roughly 1KB; at 10,000 QPS that is about 10MB/sec of read traffic, which is easily within network capacity for a co-located store. The real risk to the 10ms budget is not throughput headroom but tail behavior: a single slow shard (due to a compaction pause, a GC pause, or a hot key sharing that shard) can push a fraction of requests past 10ms even though the median is comfortably under budget, which is why the fallback strategy matters as much as the happy-path architecture.
Trade-offs & pitfalls: Grouping all 50 features into one serialized blob is efficient for retrieval but makes partial updates expensive (updating one feature means rewriting the whole blob, or the write path needs a separate mechanism); a common middle ground is grouping features by update frequency (features that change together and at similar cadence share a blob) rather than putting all 50 in one record regardless of how often each changes. A hard 10ms client-side timeout without a defined fallback effectively becomes "fail the fraud check silently," which is a worse outcome than serving a slightly stale feature in most fraud use cases, so the fallback behavior needs to be a deliberate product decision, not an afterthought bolted on after the design is built.
Unlock Full Question Bank
Get access to all 49 ML Feature Pipelines and Feature Stores interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.