Design an Online Auction System
DifficultyMedium | HelloInterview: problem breakdown
Problem Statement
Design an online auction system where sellers list items, bidders place bids, and the highest bidder at auction close wins the item.
๐Real-world: Auctions are a consistency + correctness problem dressed as a real-time one โ money and fairness are on the line, so two bids arriving at nearly the same instant must be serialized deterministically (process bids per-item through a single ordered path, often a per-auction queue or optimistic concurrency with version checks) or you get the classic bug: two people both "win." The famous real-world wrinkle is sniping โ bidders firing winning bids in the final second, which eBay studied extensively and which led some sites to adopt anti-snipe auto-extensions (any bid in the last minute pushes the close out). Live price updates fan out over WebSocket/pub-sub, but the bid-acceptance path needs strong consistency. Security/integrity angles: shill bidding (sellers using fake accounts to inflate prices) and auction fraud are core trust problems, and the auction-close event is a scheduled-job correctness concern (exactly-once close, no missed auctions) โ tying back to the job scheduler patterns.
Requirements
Functional
- Create auction listing (item, starting price, duration)
- Place a bid (must exceed current highest bid)
- Real-time current price display
- Auction close: notify winner, charge payment, notify seller
- Bid history
Non-Functional
- Bid acceptance latency: < 500ms
- Bids cannot be duplicated or lost
- Bidding during last seconds is high-concurrency (auction sniping)
- Consistent: only one winner; price must not be undercut by a lower bid
Core Design
Bid Consistency: The Hard Part
Accepting a bid requires:
- Check if bid > current highest bid (conditional)
- Write new bid if condition is true (update)
This is a compare-and-swap (CAS) operation. Under concurrent bids, two bidders may both check the price simultaneously and both think they've won.
Solution: optimistic locking in the DB
-- Atomic: only update if current_price hasn't changed
UPDATE auctions
SET current_price = $new_bid, winning_bidder_id = $bidder_id, version = version + 1
WHERE auction_id = $id AND version = $expected_version AND current_price < $new_bid
-- Check affected rows: if 0, someone else won the CAS โ return "outbid"Alternative: Redis atomic operations
-- Lua script in Redis: atomic check-and-set
local current = redis.call('GET', 'auction:' .. auction_id .. ':price')
if current < new_bid then
redis.call('SET', 'auction:' .. auction_id .. ':price', new_bid)
redis.call('SET', 'auction:' .. auction_id .. ':winner', bidder_id)
return 1 -- accepted
else
return 0 -- outbid
endAuction Sniping (Last-Second Bids)
In the final seconds, many bids arrive simultaneously. Solutions:
if bid arrives in last 2 minutes, extend by 2 minutes. Prevents sniping; eBay doesn't do this, but art auction houses do.
all bids in final period go into a per-auction queue, processed in order.
Auction Close
Scheduled job (or timer service):
At auction.end_time:
- Query highest bid (already in DB)
- Mark auction as CLOSED, winner = highest bidder
- Charge winner's payment method
- Notify winner + seller
- Update inventoryReal-time broadcast: SSE/WebSocket to all watching the auction for current price updates.
Architecture
Bid API โ Bid Validator โ Redis (atomic CAS) โ Bid DB (Cassandra: all bids history)
โ (if accepted)
Auction DB (Postgres: current state)
โ
Pub/Sub (broadcast price update)
โ
WebSocket โ all watchers
Auction Close Service (scheduled):
Timer โ Check auctions.end_time โ Close โ Payment Service โ NotificationSecurity Considerations
| Threat | Mitigation |
|---|---|
| Bid manipulation (fake bids) | Account verification; payment method on file before bidding |
| Seller shill bidding (seller bids on own item) | Block bids from seller's account/IP on their own auctions |
| Price manipulation via CAS race | DB optimistic locking ensures only one valid winner per price |
| Payment fraud | 3DS2; payment authorization hold at bid, charge on win |
| Auction extension abuse | Rate limit bids in final window; CAPTCHA for suspicious velocity |
Interview Tips
optimistic locking in DB is the clean answer.
mention extend-on-bid as one policy option; shows you've thought about the business rules.
Redis for the hot auction state (current price, winner) + Postgres for auction metadata + Cassandra for all bid history.