After studying this material, students should be able to:
Machine learning models depend on signals (features) to make predictions. The quality of those predictions depends directly on how current those signals are.
User presses "Purchase"
↓
Model must decide in MILLISECONDS
↓
Needs to know:
├── Last 30 days avg transaction amount → Historical baseline (who is this user normally?)
└── Last 10 minutes total transactions → Fresh signal (what are they doing RIGHT NOW?)
Key Insight: Without the fresh signal, the model cannot detect fraud happening in the moment
| Approach | Latency | Problem |
|---|---|---|
| Batch Spark jobs | Minutes to hours | Too slow for real-time decisions |
| Custom streaming | Seconds | Requires complex infrastructure built by hand |
| Databricks Feature Store | ~200ms | Managed, declarative, automated |
Aggregation features summarize raw events over a time period:
Raw events:
Transaction $50 → 10:01am
Transaction $200 → 10:05am
Transaction $75 → 10:08am
Aggregation (sum, last 10 min) = $325
Common aggregation types:
TUMBLING WINDOW (non-overlapping, fixed)
|--10min--|--10min--|--10min--|
Batch 1 Batch 2 Batch 3
SLIDING WINDOW (overlapping, fixed step)
|--10min--|
|--10min--|
|--10min--|
ROLLING WINDOW (continuous, event-driven)
Every new event immediately updates the aggregate
New event → instant recalculation → instant update
| Window Type | Best For | Update Frequency | Cost |
|---|---|---|---|
| Tumbling | Stable, infrequent features | Low | Cheapest |
| Sliding | Moderate freshness needs | Medium | Moderate |
| Rolling | Maximum freshness | Every event | Higher |
Rule of thumb: Use rolling windows when every new event should immediately change the value the model sees
The Feature Store lets you define this simply:
# Conceptual example of the declarative API
feature = RollingWindowFeature(
name="user_transaction_sum_10min",
entity="user_id",
aggregation="sum",
column="transaction_amount",
window="10 minutes"
)
One definition → drives both batch and streaming pipelines automatically
Kafka (raw events)
↓
Spark RTM (Real-Time Mode)
├── Stage 1: Data Processing
│ └── Schema validation, type casting, coalescing
├── Stage 2: Aggregation
│ └── RocksDB (local state) → rolling window calculation
↓
Lakebase (online feature store)
↓
Model Serving (inference)
↓
ML Model Decision
Event arrives: User buys $200 item
↓
Kafka receives event with:
- user_id: 12345
- amount: $200
- timestamp: now
- location, merchant info...
↓
RTM Stage 1: Validate and shape the data
↓
RTM Stage 2:
- Look up user 12345 in local RocksDB
- Current running total: $125 (from last 10 min)
- Add $200 → new total: $325
- Remove expired events (older than 10 min)
- Write $325 to Lakebase
↓
Model query arrives: "Should I approve this transaction?"
- Fetch fresh feature: $325 (10-min sum)
- Fetch batch feature: $45 avg (30-day baseline)
- $325 >> $45 baseline → HIGH FRAUD RISK
↓
Decision: DECLINE
MICROBATCH MODE:
─────────────────────────────────────────────────
Collect events → Process batch → Checkpoint → Collect events → ...
(wait) (wait) (wait) (wait)
Minimum latency: SECONDS to MINUTES
Each stage must FINISH before the next begins
─────────────────────────────────────────────────
REAL-TIME MODE:
─────────────────────────────────────────────────
Stage 1 ──→ processes row immediately
↓ (passes row forward without waiting)
Stage 2 ──→ aggregates row immediately
↓
Lakebase ──→ updated immediately
Stages run CONCURRENTLY, not sequentially
─────────────────────────────────────────────────
Analogy: MBM is like a factory that waits until 100 items are built before moving them to the next station. RTM moves each item to the next station the moment it's ready.
Each executor maintains a local RocksDB instance:
Why RocksDB?
├── Runs locally on each executor (no network round-trip)
├── Can store state LARGER than available memory (disk-backed)
├── Fast key-value lookups by entity (e.g., user_id)
└── Handles window expiration per-row
| Aspect | Microbatch | RTM |
|---|---|---|
| When checkpointed | Every batch boundary | Every 5 minutes |
| Effect on latency | Blocks pipeline each time | Cost spread across many rows |
| Fault tolerance | Full | Full (replays ≤5 min of Kafka data) |
| Recovery cost | Lower replay | Slightly higher replay |
Key tradeoff: RTM accepts slightly more replay data on failure in exchange for dramatically lower steady-state latency
You don't manage:
✗ Cluster provisioning
✗ Executor tuning
✗ Capacity planning
✗ Maintenance windows
Databricks handles:
✓ Auto-scaling
✓ Zero-downtime restarts (synchronized at 5-min checkpoints)
✓ Infrastructure updates
Lakebase is Databricks' online feature store — a Postgres-compatible database optimized for:
Standard Postgres WAL behavior:
─────────────────────────────────────────────────
Event updates user 12345's feature value
↓
Postgres writes FULL 8KB page to WAL
(even though only a few bytes changed)
↓
Next update to same user → ANOTHER full 8KB page
↓
High-frequency updates = MASSIVE WAL bloat
= Bottleneck for writes, replication, recovery
─────────────────────────────────────────────────
Lakebase architecture:
─────────────────────────────────────────────────
Event updates user 12345's feature value
↓
Lakebase writes SMALL compact change record
(only the actual change, not full page)
↓
Quorum of distributed safekeeper nodes
acknowledge durability
↓
Full page snapshots generated LATER in storage layer
(not in the write path)
─────────────────────────────────────────────────
Result: Far less WAL amplification
Continuous fresh writes possible
Durability still guaranteed
Lakebase
├── Compute layer: Scales independently
│ └── Handles variable inference load
└── Storage layer: Distributed, durable
└── Handles streaming write volume
Result: Autoscales to handle spikes in model inference
without affecting write performance
Model logged with MLflow
↓
Feature dependencies automatically recorded
↓
At inference time:
Request arrives → Model Serving automatically:
1. Looks up required features from Lakebase
2. Joins features with inference request
3. Passes complete feature vector to model
4. Returns prediction
↓
No custom lookup code needed
No manual plumbing
The problem: Streaming features use short retention windows on Kafka — historical data disappears
The solution:
Databricks Feature Store:
├── Stores offline copy of ingested Kafka data
├── Calculates same feature values as streaming pipeline
│ (for historical periods)
└── Does point-in-time accurate joins for training
(no data leakage — only uses data available at that moment)
Also enables: Fast backfilling of online features for new deployments
Features are first-class objects:
├── Discoverable (searchable catalog)
├── Access-controlled (who can use which features)
├── Lineage tracked (which model uses which features)
└── MLflow captures feature-to-model dependencies
Result: One platform for develop → deploy → govern
┌─────────────────────────────────────────────────────────┐
│ Databricks Feature Store │
│ │
│ Define once → Use everywhere │
│ │
│ Kafka → [Spark RTM] → [Lakebase] → [Model Serving] │
│ │
│ End-to-end p99 latency: 200ms │
└─────────────────────────────────────────────────────────┘
| Component | Role | Key Optimization |
|---|---|---|
| Spark RTM | Continuous stream processing | Concurrent stages, per-row aggregation |
| RocksDB | Local state for aggregations | No network latency, disk-backed |
| Lakebase | Online feature storage | Compact WAL writes, compute-storage separation |
| Model Serving | Feature retrieval at inference | Automatic feature lookup, high QPS |
| Unity Catalog | Governance and lineage | Discoverable, access-controlled features |