06
Deep Dive — Auction Engine Serialization
The Redis Lua script is the heart of the system. Every bid — manual or proxy — is processed atomically in a single Lua execution. Redis's single-threaded model guarantees linearizability by construction: no locks, no retries, no race conditions. The script validates, accepts, resolves proxies, checks anti-snipe, and returns the outcome in ~0.5ms.
Why Naive Approaches Fail
PostgreSQL Optimistic
UPDATE WHERE current_price = expected. Under contention, retry storms: bid N+1 retries after N succeeds. At 50 bids/sec, latency explodes.
SELECT FOR UPDATE
Row lock held for 5-20ms (network + fsync). 50th bid waits 500ms in queue. App crash holds lock for 30 seconds.
The Lua Script Pipeline
The script executes in 7 steps, all within a single atomic Redis call:
1. Read state — HGETALL auction state (~0.1ms). 2. Validate — auction active, not expired, not seller, not already highest, amount ≥ min. 3. Accept bid — update price, highest bidder, increment count. 4. Resolve proxies — mathematical resolution: winner pays min(loser_max + increment, winner_max). No iterative loop. 5. Anti-snipe — if within window and extensions remaining, extend end_time. 6. Write state — HMSET updated fields (~0.1ms). 7. Return — JSON result with outcome, price, flags.
Proxy Resolution — The Vickrey Formula
When two proxies compete (Alice max $500, Bob max $350), the result is computed in one step: Alice wins at min($350 + increment, $500) = $360. No looping through 35 counter-bids. Tie-breaking uses a composite score encoding max × 10¹³ + (10¹³ − timestamp), so the earlier proxy wins ties.
sequenceDiagram
participant C as Client
participant GW as API Gateway
participant BS as Bid Service
participant R as Redis (Lua)
participant K as Kafka
participant WS as WebSocket Tier
C->>GW: POST /bids (amount=$500)
GW->>GW: Auth + Rate Limit
GW->>BS: Forward + X-Received-At
BS->>BS: Idempotency check
BS->>R: EVALSHA bid_processor.lua
R->>R: Validate → Accept → Proxy resolve → Anti-snipe
R-->>BS: {ok:true, outcome:OUTBID, price:510}
BS-->>C: 200 OK (45ms total)
BS->>K: Publish BID_ACCEPTED
K->>WS: Consumer reads event
WS->>WS: Personalize per-connection
WS-->>C: Push: BID_UPDATE (80ms)
Critical Constraint: Script Must Complete in <2ms
Redis is single-threaded. While the Lua script runs, ALL other commands on that shard are queued — including bids for other auctions. At 0.5ms average with 50 ops/sec on a hot key, we consume only 25ms/sec of Redis time. The sorted set operations (proxy lookup) are O(log N) due to skip list internals. Monitoring: p99 script time > 1ms triggers an alert; > 2ms triggers investigation.