HomeResourcesCase study
Case study

You Can't Autoscale a Bank

By The SDL team·4 min read·Updated Sep 16, 2026

Razorpay's flash-sale limiter wasn't protecting their servers. It was protecting a partner they couldn't scale.

Most rate-limiting advice is about protecting your own servers. Razorpay's flash-sale problem was sneakier: their servers were fine. The thing that would break was a bank they didn't own and couldn't scale.

During a flash sale, a wall of payment requests hits at once. Razorpay can autoscale their own infrastructure — but every payment ultimately flows through an external bank gateway, and you cannot send a bank an autoscaling request. Overrun it and it degrades for everyone, including non-sale traffic.

Plain English

A rate limiter caps how many requests you let through per unit of time. The usual reason is to stop your own service from being overwhelmed. But there's a second, subtler reason: to protect a downstream dependency you don't control. If your payments flow through a partner that can only handle so much, you must throttle before you flood them — because their failure becomes your failure.

So the limiter isn't selfish protection. It's being a good citizen to a fragile partner, on whom your success depends.

Now the engineering

Razorpay put a rate limiter in an Nginx sidecar at the edge, implemented as a fixed-window atomic counter with a TTL: count requests in the current time window, reject past the cap, reset when the window expires. Simple and fast — the atomic counter avoids race conditions under concurrency, and putting it in a sidecar keeps the logic next to the proxy rather than buried in application code.

On top of throttling, they added ML-based gateway routing: rather than sending payments to a fixed or round-robin bank gateway, a model predicts each gateway's current success probability and routes accordingly — steering traffic away from a struggling gateway before it tips over. And critically, they used k6 load testing to find the true bottleneck before a real sale did, so the caps were grounded in measured limits, not guesses.

A rate limiter protects what you don’t control: the bank gateway flash-sale flood Nginx sidecar limiter fixed-window atomic counter ML gateway router picks by success prob. bank gateway A (flaky) bank gateway B (healthy) The danger: you can autoscale your own servers, but you CANNOT autoscale a bank. Overrun a gateway and it fails everyone — so you must throttle BEFORE it. Sustained ~1500 requests/sec through flash sales by shaping load at the edge k6 load tests find the real ceiling before the sale does.
Throttle for the partner you can't scale. A fixed-window limiter at the edge plus success-probability routing keeps external bank gateways from being overrun.
~1500/s
sustained through sales
fixed-window
limiter algorithm
k6
ceiling found pre-sale

Worth knowing

The fixed-window counter has a known flaw — bursts straddling the window boundary can briefly allow 2x the limit (which is why sliding-window or token-bucket exist). Razorpay's choice is a reminder that the right algorithm is the simplest one that holds for your traffic shape, not the most sophisticated. Knowing the trade-off lets you defend the choice instead of cargo-culting the fanciest option.

The gap it reveals

Rate limiting is taught as self-defence. The realisation that matters in payments and integrations is that you often limit to protect a downstream you can't autoscale — an external gateway, a legacy system, a partner API — and that the smart move pairs throttling with health-aware routing. Most candidates think 'protect my service'; the senior thinks 'protect the weakest link in the chain.'

In the interview room

Any design with a third-party dependency (payment gateway, SMS provider, partner API) invites: "what happens when that dependency is the bottleneck?" Strong answer: rate-limit at your edge to stay within the partner's capacity, route away from unhealthy instances, and load-test to discover the real ceiling. Naming the fixed-window-vs-token-bucket trade-off is a bonus that shows depth.

The reframe

Your system's reliability is capped by its least scalable dependency, and that dependency is often something you don't own. Scaling your own servers feels like progress, but if you're just delivering more load to a fragile partner faster, you've moved the failure, not removed it. The mature move is to find the real ceiling and shape traffic to respect it.

You can't autoscale a bank. Throttle before the thing that can't grow.

Primary source →
systemdesign.one — How Razorpay Scaled to Handle Flash Sales at 1500 RPS

Want feedback on your design?

The weekly teardown

One real-world architecture, every week.

How real companies actually built it: the design, the trade-offs, and what to say about it in an interview. Free, and one click to unsubscribe.

Related articles