The Quest Begins (The "Why")

Ever had one of those days where your API feels like it’s stuck in quicksand? I was building a simple rate‑limiter for a microservice that throttles requests per IP address. The idea was straightforward: every incoming hit checks a counter stored in Postgres, increments it, and if the counter exceeds the limit we return 429.

At first it worked like a charm on my laptop. Then we pushed to staging and… boom. Latency spiked from 2 ms to 200 ms under a modest load of 500 RPS. I felt like Neo in The Matrix before he sees the code—everything looked fine, but there was a hidden bug chewing up CPU cycles.

I dug into the query plan:

SELECT count FROM rate_limits WHERE ip = $1 FOR UPDATE;