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.
You need low-latency online feature retrieval. Compare Redis, Cassandra, and DynamoDB as backing stores for an online feature store. For each, discuss latency, throughput, consistency model, scaling characteristics, operational burden, cost, and suitability for high-cardinality entities.
Sample Answer
Direct answer: For an online feature store you are choosing among low-latency key-value systems, and the three most common are Redis, Cassandra, and DynamoDB. Redis wins on raw latency (sub-millisecond, in-memory) but costs more per GB and needs careful sizing since it is memory-resident. Cassandra and DynamoDB trade a few milliseconds of latency for durability and horizontal write scale without you managing replica failover by hand (DynamoDB is fully managed; Cassandra is self-managed or managed-service).
Structured elaboration:
| Dimension | Redis | Cassandra | DynamoDB |
|---|---|---|---|
| Typical p99 read latency | 0.3-1ms (in-memory) | 2-10ms (SSD-backed) | 1-9ms (network + SSD) |
| Throughput scaling | Vertical + Redis Cluster sharding | Horizontal, linear with nodes | Horizontal, auto-scaling built in |
| Consistency | Single-node strong; cluster is eventually consistent across shards during failover | Tunable per-query (ONE/QUORUM/ALL) | Eventually consistent by default, strongly consistent reads available at 2x cost |
| Durability | Optional (RDB/AOF); primarily an in-memory cache unless configured carefully | Durable, replicated (default RF=3) | Durable, replicated across AZs |
| Operational burden | You manage sharding, failover, memory eviction policy | You manage the cluster, compaction, repair | Fully managed, pay-per-request or provisioned capacity |
| Cost at scale | High (RAM-priced) unless data fits comfortably in memory | Lower (SSD-priced), higher ops cost | Pay-per-use can get expensive at very high steady QPS; no ops cost |
| High-cardinality entities | Handles well if working set fits in RAM; needs an eviction/time-to-live (TTL) strategy otherwise | Handles very well, partition key spreads load | Handles well; watch for hot partition keys (see the hot-key sub-area) |
Suitability rule of thumb: if the working set fits in memory and you need the lowest possible tail latency (fraud scoring, real-time bidding), Redis is the default choice, often fronted by a thin caching layer even in front of another store. If you need durability without operating a cache-warming story, and write volume is high and steadily growing, DynamoDB (if you are already on AWS and want zero ops) or Cassandra (if you need multi-cloud portability or already run it) are the better fit.
Worked example: Say you serve 50 features per user at 10,000 QPS (queries per second) with a 10ms p99 budget. A single Redis Cluster node handles roughly 100k-200k simple GET ops/sec depending on payload size and pipelining, so 10,000 QPS is comfortably inside a 3-6 node cluster's capacity with headroom for replication reads. The same workload on DynamoDB, provisioned for 10,000 reads/sec (or on-demand), meets the 10ms budget for the vast majority of requests but has a longer tail because each read is a network round trip to a multi-tenant service, not an in-process memory read; you would typically add a small local or Redis-based cache in front of DynamoDB for the hottest keys to flatten that tail.
Trade-offs & pitfalls: Redis-only deployments that skip persistence configuration silently become a single point of data loss on a restart; feature stores that treat Redis as the online store, not just a cache, need RDB snapshotting or a durable upstream to rebuild from. Cassandra's tunable consistency is easy to misconfigure (reading at ONE after writing at ONE gives no consistency guarantee at all, which surprises teams who assume "Cassandra is consistent"). DynamoDB's per-partition throughput limits (a single partition key tops out around 1,000 write units and 3,000 read units per second) mean a naive partition key on a viral entity ID recreates the hot-key problem discussed elsewhere in this topic, so key design has to account for it up front, not as an afterthought.
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.
What is Change Data Capture (CDC)? Name at least two commonly used CDC tools and outline how you would integrate CDC events into a downstream feature pipeline while preserving low latency and correctness.
Sample Answer
Direct answer: Change Data Capture (CDC) is a technique for continuously capturing row-level insert, update, and delete events from a source database (typically by reading its transaction/write-ahead log) and streaming them to downstream consumers, rather than periodically polling or bulk-exporting the whole table.
Structured elaboration:
- Debezium: an open-source CDC platform that reads a database's write-ahead log (Postgres's logical replication slots, MySQL's binlog, etc.) and publishes row-level change events to Kafka; it is the most widely used open-source option and supports many source databases through connectors.
- AWS DMS (Database Migration Service): a managed AWS service that supports both one-time bulk migration and ongoing CDC replication from a source database to a target (which can be another database, S3, or a stream); convenient if you are already on AWS and want a managed CDC pipeline without operating Debezium/Kafka Connect yourself.
- Confluent's CDC connectors: source connectors within the Kafka Connect ecosystem (often built on Debezium under the hood) that integrate tightly with a Confluent-managed Kafka deployment.
Integrating CDC into a downstream feature pipeline: the CDC tool publishes a stream of change events (each carrying the changed row's before/after state and the operation type) to a message queue (typically Kafka); a stream processor consumes that change stream, applies any needed transformation (deriving a feature from the changed row, or simply passing through updated field values), and writes the result to the feature store's online and/or offline path. Because CDC captures changes as they commit to the source database's log, latency from a source-table write to a downstream feature update can be in the seconds range, much lower than a periodic batch export. To preserve correctness, the pipeline needs to process change events in the order they were committed per row (most CDC tools preserve per-key ordering) and apply idempotent writes downstream, since CDC connectors typically guarantee at-least-once delivery, not exactly-once.
Trade-offs & pitfalls: CDC adds an operational dependency on the source database's replication mechanism (a logical replication slot in Postgres, for example, must be actively consumed or it can cause the source database's write-ahead log to grow unbounded and eventually threaten the source database's own disk space); a CDC pipeline that falls behind or stops consuming is not just a downstream data-freshness problem, it can become a source-database incident. Schema changes on the source table (a column added or renamed) need to be handled by both the CDC connector and every downstream consumer, since CDC events reflect the source schema directly and a breaking change there propagates immediately to every consumer of the change stream.
Explain schema evolution: what it is, why it matters for feature pipelines, and how commonly used serialization formats (Avro, Parquet, Protobuf) support it. Describe a process for handling a breaking schema change in a production streaming pipeline that has multiple downstream consumers.
Sample Answer
Direct answer: Schema evolution is the practice of changing a data schema over time (adding, removing, or modifying fields) while keeping existing producers and consumers working, and formats like Avro, Parquet, and Protobuf support it through explicit compatibility rules and a schema registry that tracks versions.
Structured elaboration:
- Why it matters for feature pipelines. A feature pipeline has many producers (upstream services or teams writing events) and many consumers (transformation jobs, models, other teams' pipelines); if a schema change breaks any consumer, the failure can be silent (a consumer misinterprets a field) or loud (a consumer crashes), and both are costly to debug after the fact, so having explicit rules for what changes are safe is far cheaper than discovering the hard way.
- How Avro, Parquet, and Protobuf support it. Avro attaches the writer's schema to the data (or references it via a schema registry) and defines resolution rules for reading data written with an older or newer schema than the reader expects; adding a field with a default value is backward compatible, removing a field a reader depends on is not. Parquet stores its schema in the file's footer and supports schema merging across files with compatible-but-not-identical schemas (commonly used when a table's schema evolves over time across many files), though it relies more on the query engine to reconcile differences than Avro's explicit reader/writer resolution. Protobuf uses numbered fields, where adding a new numbered field is safe (old code ignores it, new code sees it as absent/default in old data) and reusing or renumbering an existing field number is unsafe (it silently reinterprets old data incorrectly).
- Compatibility models. Backward compatibility means new code can read data written by old code (safe: adding an optional field); forward compatibility means old code can read data written by new code (safe: old code ignoring a new field it doesn't know about); full compatibility requires both directions to hold simultaneously, which is the strictest and safest guarantee for a shared schema used by many independent consumers who upgrade on different schedules.
- Handling a breaking change with multiple consumers. For a genuinely breaking change (renaming a field, changing its type incompatibly), the standard process is: introduce the new field alongside the old one (dual-write), migrate consumers to the new field on their own schedule, monitor until no consumer is still reading the old field, then remove the old field in a later, separate release, rather than attempting an atomic cutover across every consumer simultaneously.
Worked example: Adding a new optional device_type field to an event schema with a default value of "unknown" is backward compatible under all three formats: existing consumers that do not know about the field simply ignore it, and consumers upgraded to read it get "unknown" for historical data that predates the field's introduction, with no reprocessing required.
Trade-offs & pitfalls: A schema registry enforcing compatibility checks at write time (rejecting a producer's schema change that would break existing consumers) is the strongest guardrail, but it requires the discipline of registering every schema change through the registry rather than a producer silently writing a new shape; a team that bypasses the registry (writing raw JSON with no enforced schema, for example) loses this protection entirely and reintroduces the risk the registry exists to prevent. The dual-write-then-migrate-then-remove pattern for breaking changes is the safe default, but it is slower than a direct cutover, and teams under time pressure sometimes skip the migration step and go straight to removing the old field, which breaks any consumer that had not yet migrated, often silently.
Explain watermarking and windowing in stream processing for feature computation. Define tumbling, sliding, and session windows and give a short example of each (for example: tumbling for hourly aggregates, sliding for rolling counts, session for bursts of user activity).
Sample Answer
Direct answer: Watermarking is a stream processor's mechanism for deciding when it is safe to say "no more events for this window will arrive," and windowing is how it groups events by time into aggregation buckets. A watermark is a heuristic timestamp (typically max-observed-event-time minus an allowed-lateness slack) below which the engine assumes all events have been seen.
Structured elaboration:
- Tumbling windows: fixed-size, non-overlapping windows (e.g. every 60 seconds). Example: computing hourly click counts per user, where each event belongs to exactly one hour bucket.
- Sliding windows: fixed-size windows that overlap, advancing by a slide interval smaller than the window length (e.g. a 10-minute window sliding every 1 minute). Example: a rolling "clicks in the last 10 minutes" feature that updates every minute rather than jumping discretely every 10 minutes.
- Session windows: dynamic-length windows defined by a gap of inactivity (e.g. close the session after 30 minutes with no events). Example: grouping a user's browsing activity into "sessions" for a feature like "number of pages viewed this session," where the window boundary is data-driven, not fixed.
- Watermarking's role: without a watermark, the engine would have to wait forever before emitting a window's result, since a late event could theoretically still arrive. The watermark trades a small amount of completeness (events later than the watermark are dropped or handled specially) for the ability to emit timely results.
Worked example: For an hourly tumbling window with a 5-minute allowed lateness, the watermark at wall-clock time 10:07 (assuming events have been arriving roughly on time) is approximately 10:02; the 9:00-10:00 window closes and emits once the watermark passes 10:00, which happens once the engine has seen an event timestamped 10:05 or later.
Trade-offs & pitfalls: A too-tight allowed-lateness closes windows quickly (good for freshness) but drops more genuinely late data, understating aggregates; a too-loose allowed-lateness keeps more state in memory for longer and delays results. Session windows are the trickiest of the three to reason about because the window boundary itself depends on the data, so a single very-delayed event can retroactively extend a session that had appeared to close, which downstream consumers need to be able to handle (either by accepting a late correction or by explicitly closing sessions eagerly and accepting the resulting inaccuracy for outlier cases).
Unlock Full Question Bank
Get access to hundreds of ML Feature Pipelines and Feature Stores interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.