Skip to main content
FomiVIP
Tech Sharing

Redis Caching and Rate Limiting for Expo QR Signup Peaks

Expo QR signups peaked at 600+ submissions per minute — with no extra machines. Three layers: Nginx per-IP rate limiting, Redis signup state with debouncing, and an idempotency key before every database write. Static pages on CDN, submissions on a separate domain. Three hours on-site, zero 502s.

March 6, 2026Rate LimitingCachingOn-Site Ops

A trade show in March, with QR-based signup, and the half hour after doors open is the crunch. Before launch we didn't ask for more machines — we just stopped what we could at the gate.

Three Layers

Layer one is Nginx. Per-IP rate limiting: 20 requests per minute per IP, beyond that a straight 429. At a trade show everyone shares one Wi-Fi egress — dozens of phones behind a single public IP. This threshold took two rounds of tuning: we started at 10 and caught a batch of legitimate users; 20 smoothed it out. Configured with limit_req_zone, burst of 5.

Layer two is Redis. The signup page reads registration state, which used to hit the database every time. Now Redis holds a copy with a 300-second TTL; tapping the same QR code twice within 10 seconds returns the previous result without going further. Flaky venue networks make double taps easy.

Layer three sits before the database write. The idempotency key is the QR token plus the last four digits of the phone number; within 60 seconds, duplicates write only one record and repeat submissions return the existing entry. This is the safety net — anything the first two layers miss stops here.

Splitting Static Assets from Submissions

The page itself, QR images, and styles all go to CDN, filenames carrying content hashes, cached 30 days. Form submissions go through a separate submit domain — explicitly not cached or accelerated by CDN, straight to origin, the same pattern we used for the 2020 event site. The first version tried to save effort with a shared domain, and POSTs got 403'd at the edge nodes.

On-Site

March 6, doors at 9 a.m. Peak was 600+ submissions per minute. Redis CPU stayed flat, and MySQL write QPS topped out in the low 80s — most duplicates had already been filtered upstream.

The 200+ requests blocked by 429 were, per the logs, mostly a single barcode scanner firing continuously, plus a few people repeatedly refreshing the result page. Legitimate signups were unaffected.

Three hours, zero 502s. The queue peaked at just over 30 items and drained in two minutes.

A Note in Hindsight

Rate limiting thresholds aren't calculated — they're tested against the real network. How many people actually sit behind one egress IP? You only know on-site. So that day we kept the threshold in a config that can be changed anytime — no code changes, no restart, just a reload. And we really did change it twice.

When it ended we exported a CSV, 2,000+ rows, split into 3 sheets by signup source. By then the venue was tearing down booths, our QR stand was leaning to one side, and the protective film was still half on.

Consulting · Free initial chat

Need advice for your scenario?

Tell us your business context and current systems, and we'll give an actionable approach.

Contact us

Mon–Fri 9:00–18:00 · We respond on business days within one business day.

WeChat (Business Only)
WeChat (Business Only)二维码

Scan and add our WeChat for consulting

Or fill out the requirements form