Sub-millisecond redirects with Go and Redis
What it actually takes to serve 14k requests a second from a link shortener — connection pooling, cache warming, and the profiling that found the real bottleneck.
A link shortener looks trivial: look up a code, return a 301. The interesting part is doing it at 14,000 requests a second on one modest box without the tail latency creeping up. Most of the work was measurement, not cleverness.
01The naive version
The first cut opened a Redis connection per request and did a synchronous
GET. It worked — until concurrency climbed and the p99 fell off a cliff. The
culprit wasn't Redis; it was churning TCP connections.
func redirect(w http.ResponseWriter, r *http.Request) {
code := path.Base(r.URL.Path)
url, err := rdb.Get(r.Context(), "u:"+code).Result()
if err != nil {
http.NotFound(w, r)
return
}
http.Redirect(w, r, url, http.StatusMovedPermanently)
}
02Pooling first
Sharing one pooled client across all handlers flattened the p99 immediately.
Once the pool was in place, profiling pointed somewhere I didn't expect.
03What the profile showed
A CPU profile of the hot path put most of the time in two places:
- Allocating the
"u:" + codekey string on every request. - JSON-decoding a value that never needed to be JSON.
Fixing both — a pre-sized key buffer and storing the raw URL as a plain string — cut allocations per request to near zero and pushed throughput past 14k/s.
The warm-cache detail
Cold starts still spiked because the first hit for each code missed the local in-process cache. Warming the top few thousand codes on boot removed the spike entirely.
Performance work is a loop: measure, change one thing, measure again. Guessing is how you optimize the wrong line for a week.
The final service is a few hundred lines of Go. The speed came from deleting work, not adding it.