Designing an E-Commerce Platform
One platform, two completely different consistency requirements: inventory can never lie, and search can lag by seconds without anyone noticing.
Overview
An e-commerce platform is a genuine polyglot persistence case study: inventory counts need the same strong-consistency guarantees as the payment system two chapters back, while product search behaves much more like the feed architecture in the previous chapter — no single storage system fits both halves of this platform well.
Why It Exists
Overselling a product — accepting more orders than there's actual stock for — is a direct, visible failure with real business cost. A product search result that's a few seconds out of date after a catalog update is invisible to almost every shopper. This chapter exists to show that 'one system, one consistency model' is often the wrong framing entirely — a well-designed e-commerce platform deliberately uses different storage systems for different parts of the same product, each matched to its own actual consistency requirement.
Real World Example
During a flash sale, 500 shoppers simultaneously try to buy the last 10 units of a product. The inventory count lives in a relational database, decremented inside an ACID transaction with row-level locking, so exactly 10 orders succeed and the rest see 'out of stock' — no overselling, even under that exact race condition. Meanwhile, the product's search ranking and description in the catalog search index might still reflect a stock count from 30 seconds ago, and it doesn't matter at all — a shopper seeing a slightly stale 'in stock' badge in search results, who then gets an accurate answer at checkout, isn't a real problem.
One Platform, Several Storage Systems
Inventory Ledger — Strong Consistency to Prevent Overselling
Stock counts live in a relational database, decremented inside ACID transactions with row-level locking, so concurrent purchase attempts against the last few units of a product are correctly serialized rather than racing.
Product Catalog Search — An Inverted Index, Eventually Consistent
Product search and browsing run against a search engine (see Search & Inverted Indexes) built for full-text and faceted search — updated asynchronously from the source-of-truth catalog, tolerating a short staleness window in exchange for fast, flexible search.
Product Images — Object Storage With Pre-Signed Upload URLs
Sellers upload product images directly to object storage using a pre-signed URL generated by the application server, so large image files never have to be proxied through the application's own compute — only the temporary, authenticated URL does.
The Shopping Cart — a Cache-Backed, Short-Lived Store
An in-progress cart is read and written far more often than an order is finalized, and doesn't need long-term durability guarantees — a fast key-value cache like RedisA single-threaded, in-memory key-value data structure store, commonly used for caching, sessions, and rate limiting.Learn more fits this access pattern well, with the order only becoming a durable, ACID-committed record at checkout.
Diagram
Different consistency needs, routed to different storage systems
Checkout: decrement inventory
ACID transaction, relational DB
Browse: search the catalog
search index, eventually consistent
Upload: product image
pre-signed URL → object storage directly
Shop: manage cart
Redis — fast, short-lived
Common Mistakes
Treating the search index as the source of truth for whether a product is actually in stock
Why: Search indexes are typically updated asynchronously and can lag behind the real inventory count — checking availability against the index rather than the transactional inventory system risks overselling.
Fix: Always verify and decrement stock against the strongly consistent inventory database at the moment of purchase, regardless of what the search index shows.
Not accounting for JVM Garbage Collection pauses in a JVM-based search cluster (like Elasticsearch) under heavy indexing load
Why: Large heap sizes and frequent catalog updates can trigger long garbage-collection pauses, causing visible search latency spikes or timeouts exactly when traffic is highest, like during a sale.
Fix: Size the search cluster's heap and indexing rate with GC behavior in mind, and monitor for GC-related latency spikes as a specific, distinct failure mode from general overload.
Proxying large product image uploads through the application server instead of using pre-signed URLs
Why: Routing every image upload through the app server consumes its compute and bandwidth for a task that object storage can handle directly, and adds unnecessary latency and a single point of failure.
Fix: Generate a pre-signed URL for each upload and let the seller's browser upload directly to object storage.
Interview Questions
Why does an e-commerce platform typically use more than one type of database?
Different parts of the platform have genuinely different requirements — inventory needs strong consistency to avoid overselling, while product search benefits from a specialized search index that can tolerate being briefly out of date. No single storage system is the best fit for both.
Why is it safe for the product search index to be eventually consistent, when the inventory count can't be?
A stale search result has essentially no real cost — a shopper might briefly see a slightly outdated stock badge or ranking, but the actual purchase is still verified against the accurate, strongly consistent inventory system at checkout. Overselling, by contrast, is a direct, visible business failure with no equivalent 'it gets corrected at the real moment that matters' safety net.
During a flash sale, your search cluster starts timing out intermittently even though CPU and memory graphs look normal. What would you investigate, and why?
I'd specifically look at JVM garbage collection logs and pause times, since a JVM-based search cluster (like Elasticsearch) under heavy indexing and query load can experience long GC pauses that cause exactly this symptom — normal-looking average resource utilization with intermittent latency spikes or timeouts, because the pause itself is a brief full stop rather than sustained high usage. If GC pauses are the cause, the fix is usually heap sizing, reducing indexing pressure during peak load, or scaling out to more, smaller nodes rather than fewer large ones — not just adding more raw CPU or memory to the existing nodes.
Production Best Practices
Do
✓Verify and decrement stock against the strongly consistent inventory database at purchase time, not the search index.
✓Monitor JVM garbage collection behavior in search clusters as a distinct failure mode from general overload.
✓Use pre-signed URLs for direct-to-object-storage uploads instead of proxying through the app server.
Don't
✗Don't treat a search index as authoritative for real-time stock availability.
✗Don't ignore GC pause times when diagnosing intermittent search latency spikes.
✗Don't route large file uploads through application server compute unnecessarily.
Comparison
| Consistency Model | Update Latency | Used For | |
|---|---|---|---|
| Inventory (Relational DB) | Strong (ACID) | Immediate | Stock counts, order transactions |
| Catalog (Search Index) | Eventual | Seconds, asynchronous | Product browsing and search |
| Cart (Redis) | None needed — short-lived | Immediate, in-memory | In-progress shopping carts |