At a glance#
| Number | Value | What it drives |
|---|---|---|
| DynamoDB peak, all of Amazon | 192 million req/s (Prime Day 2026) | platform context, not our sizing |
| Items purchased | 100,000+ a minute (Prime Day 2022) | the anchor for order rates |
| Orders at peak (assumed) | ~5,000 / s · design 20,000 | placement and pipeline capacity |
| Cart operations at peak (assumed) | ~100,000 / s · design 400,000 | cart tables, cell count |
| Cart requests per checkout | ≥10 (from the Dynamo paper's figures, 2007) | cart traffic ≫ order traffic |
| Services per page | 150+ (2007) | targets at p99.9; ~14% of pages hit a slow call |
| Hottest deal counter (assumed) | ~5,000 writes / s | split into ~20 sub-counters |
| Cells (assumed) | ~40 of up to 8M customers | one cell failing ≈ 2.5% of customers |
Architecture#
DiagramCart, checkout and orders in customer cells, on shared prices and stock
%% title: Cart, checkout and orders in customer cells, on shared prices and stock
flowchart TD
APP@{ icon: "sd:phone", label: "App and website<br/>cart · checkout" }
GW@{ icon: "sd:gateway", label: "Front door<br/>auth · priority · shed bots first" }
RT@{ icon: "sd:router", label: "Cell router<br/>customer id to cell · map in memory" }
CART["Cart service<br/>always writable · tagged lines"]:::core
CHK["Checkout and order<br/>purchase id · one transaction"]:::hot
CDB@{ icon: "sd:database", label: "Cell tables<br/>carts · orders · tokens · outbox" }
PRICE@{ icon: "sd:cache", label: "Price and promo<br/>shuffle-sharded groups" }
INV["Inventory<br/>per product and FC · sub-counters"]:::core
Q@{ icon: "sd:queue", label: "Order queues per cell<br/>live · sideline" }
ORCH["Order orchestrator<br/>authorise · release · compensate"]:::core
PAY@{ icon: "sd:bank", label: "Payment processors<br/>authorise now, capture at ship" }
FC@{ icon: "sd:warehouse", label: "Fulfilment centres<br/>one release per FC" }
APP ==> GW ==> RT
RT ==> CART
RT ==> CHK
CART --> CDB
CHK --> CDB
CHK --> PRICE
CHK ==>|"reserve"| INV
CDB -.->|"outbox"| Q
Q ==> ORCH
ORCH ==> PAY
ORCH ==> FC
class APP client
class GW,RT edge
class CDB store
class PRICE cache
class Q queue
class PAY,FC external- Two consistency regimes: the cart is availability-first and merges; order placement is correctness-first with atomic conditional writes.
- Cells by customer: cart, checkout and orders share the customer grain; price and stock are product-scoped, so they're shared and shuffle-sharded.
- The page doesn't wait for the bank: placement reserves stock and records the order; payment and fulfilment run behind a queue.
DiagramZoom-in · cells and shuffle shards
%% title: Zoom-in · cells and shuffle shards
flowchart TD
RT@{ icon: "sd:router", label: "Cell router<br/>static map · works without control plane" }
C1["Cell 1<br/>full stack · own tables"]:::core
C17["Cell 17<br/>new build lands here first"]:::hot
C40["Cell 40<br/>full stack · own tables"]:::core
SS@{ icon: "sd:hexagons", label: "Price service · 32 groups<br/>each cell gets its own 4" }
CP@{ icon: "sd:dashboard", label: "Control plane<br/>deploy one cell at a time" }
RT ==> C1
RT ==> C17
RT ==> C40
C17 ==> SS
C1 --> SS
CP -.-> C17
class RT edge
class SS service
class CP serviceKey flows#
DiagramPlace your order pressed twice · one order
%% title: Place your order pressed twice · one order
sequenceDiagram
autonumber
participant A as App
participant C as Checkout
participant I as Inventory
participant D as Cell tables
A->>C: place order · purchase id p-7f3 · cart hash h1
C->>D: seen p-7f3?
D-->>C: no
C->>I: reserve lines · key p-7f3
I-->>C: reserved at two FCs
C->>D: one transaction · token if absent · order o-88 · outbox row
Note over A,C: response lost · app retries with jitter
A->>C: place order · p-7f3 · h1
C->>D: seen p-7f3?
D-->>C: yes · o-88 · h1
C-->>A: order placed · o-88
alt same id, different cart hash
C-->>A: parameter mismatch · review your cart
endDiagramAdd to cart when the cart key is slow · never refuse
%% title: Add to cart when the cart key is slow · never refuse
sequenceDiagram
autonumber
participant P as Phone
participant S as Cart service
participant T as Cart table
participant L as Add-log
P->>S: add headphones · tag phone 12
S->>T: conditional update on cart version
alt within latency budget
T-->>S: written
else partition unreachable
S->>L: append add · same cell, other partition
L-->>S: durable
end
S-->>P: Added to Cart
Note over S,T: next read merges the add-log · removes name observed tagsDiagramPayment processor times out · unknown, not failed
%% title: Payment processor times out · unknown, not failed sequenceDiagram autonumber participant Q as Live queue participant O as Orchestrator participant P as Processor participant F as Fulfilment centre Q->>O: OrderPlaced o-88 O->>P: authorise · key o-88 P-->>O: no answer before timeout Note over O: unknown · retry later, same key, backoff and jitter O->>P: authorise · key o-88 P-->>O: authorised O->>F: release · key o-88 and FC Note over O,F: a second copy of the release is ignored
Data model#
DiagramCore entities
%% title: Core entities
classDiagram
class Cart {
+customerId : string · partition key
+version : int · conditional writes
+lines : map of tag to line
+removed : map of tag to time · tombstones
}
class CartLine {
+tag : device and counter
+sku : string
+qty : int · merge takes the larger
}
class PurchaseToken {
+key : customer and purchase id
+orderId : string
+hash : lines, total, address
}
class Order {
+orderId : string
+state : PLACED to RELEASED
+fcs : list
+reservationKey : customer and purchase id
}
class Reservation {
+key : customer and purchase id
+fc : string
+subCounter : string
+state : RESERVED or RELEASED
}
class StockRow {
+product : string
+fc : string
+onHand : int
+reserved : int
+allocated : int
}
Cart "1" --> "many" CartLine : holds
PurchaseToken "1" --> "1" Order : names
Order "1" --> "1" Reservation : holds
Reservation "many" --> "1" StockRow : draws from- Carts partition by customer id, orders by order id, stock by product and fulfilment centre; all high-cardinality.
- A hot deal's stock row is split into sub-counters of ~1,000 units on different keys; they sum to the deal quantity.
Lifecycle#
DiagramAn order, from placed to shipped
%% title: An order, from placed to shipped stateDiagram-v2 [*] --> PLACED: token, order and outbox committed PLACED --> AUTHORISED: card authorised PLACED --> PLACED: processor timeout, retry same key PLACED --> PAYMENT_PENDING_CUSTOMER: declined for good PAYMENT_PENDING_CUSTOMER --> AUTHORISED: new method authorised PAYMENT_PENDING_CUSTOMER --> CANCELLED: deadline passed, stock released AUTHORISED --> RELEASED: one release per FC RELEASED --> SHIPPED: left the FC, charge captured SHIPPED --> [*] CANCELLED --> [*] class SHIPPED ok class CANCELLED bad class PAYMENT_PENDING_CUSTOMER queue
Decisions#
| Decision | Chose | Over | Because |
|---|---|---|---|
| Cart conflicts | Tagged lines, observed removes | Union or last write wins | keeps adds and removes |
| Cart write path | Conditional write + add-log | Error when unreachable | an add is never refused |
| Duplicate orders | Purchase id from the page | Id per click | double press = one intent |
| Token and order | One transaction | Write, then record | crash leaves all or none |
| When to take stock | At placement | At add to cart | carts don't hold stock |
| Hot deal | Sub-counters | One counter row | one item can't be split |
| Blast radius | Customer cells, shuffle shards | One big fleet | bugs reach every replica |
When it breaks#
| Failure | What users see | Contain it with |
|---|---|---|
| Bad checkout build | errors in one cell | cell-by-cell deploy · roll back first |
| Cart partition slow | nothing; add accepted | add-log fallback · merge on read |
| Lost response on place order | spinner, then same order | purchase id · equivalent response |
| Payment processor down | order placed, email later | unknown state · retry same key · sideline backlog |
| Zone lost at peak | a few retried requests | provisioned for two zones · 2-of-3 write quorum |
| Bots on one cart or deal | throttled bots | per-customer limits · shed bots first |
Say it in the interview#
- Never refuse an add: Dynamo made the cart always writable; I keep that, and fix resurfacing deletes with tags and tombstones.
- One intent, one id: the checkout page mints a purchase id, recorded with the order in one transaction; a retry gets the same order.
- Same id, different cart is not a retry: reject it as a parameter mismatch instead of guessing.
- Retry at one layer: three tries at five layers is 243× the load on a failing database.
- Split the hot item, not the table: a partition split can't help one item, so a deal's stock lives in sub-counters.
- Replication copies bugs: cells and cell-by-cell deploys turn "everyone is down" into "one in forty".
- A timeout is unknown, not failed: resolve it with the same key, and drain backlogs fresh-first.