deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Pingora's apparent 6x loss to nginx traced to a blocking DNS call in the benchmark

A container benchmark put Pingora at 21k req/s against nginx's 126k until the author found getaddrinfo running on every request; after caching DNS resolution, the real gap shrank to 1.49x.

Pingora's apparent 6x loss to nginx traced to a blocking DNS call in the benchmark

A sixfold gap that didn't add up

According to a write-up on dev.to, a developer set out to measure Pingora 0.9.0 — the Rust proxy library Cloudflare runs at its edge — against nginx in conditions that matched a real deployment: a small containerized pod with two vCPUs and a CPU limit, so that no number could lean on host hardware.

The first result looked damning. A minimal reverse proxy built with Pingora served about 21,000 requests per second, while nginx handled roughly 126,000 in the same setup — a sixfold difference. The author's instinct, though, was that the figure couldn't be right: Cloudflare would not replace nginx with technology that much slower, so something in the test itself had to be at fault.

Eliminating the usual suspects

The investigation methodically ruled out the common causes of distorted container benchmarks. CPU throttling was not responsible, since the kernel's nr_throttled counter read zero. Thread oversubscription was excluded because exactly two workers were running. Connection behavior also matched, with both proxies holding around 130 upstream connections.

The real clue was latency. Inside the container, requests averaged 4.78 ms, while the same test on the host — where the backend was addressed as 127.0.0.1 — ran at 0.45 ms. The only variable that differed between the two runs was how the backend was named.

getaddrinfo, synchronously, on every request

The proxy's upstream peer selection constructed its destination on each request by passing a hostname and port to HttpPeer::new. Given a string-and-port pair rather than an address, that call resolves the name through getaddrinfo — a blocking operation executed on the tokio worker thread. Inside a container, every request therefore fired a DNS query at Docker's embedded resolver and stalled the worker while waiting for the answer. On the host, the address was an IP literal, so resolution collapsed into a simple parse with no syscall, and the cost barely registered.

A one-line fix and honest numbers

The remedy was to resolve the name once at startup, store the resulting SocketAddr, and hand that cached address to HttpPeer::new on every subsequent request. After the change, Pingora's throughput in the same pod climbed from 21,000 to about 89,000 requests per second. The sixfold deficit was the per-request name lookup, not the framework.

With the proxy written correctly, the remaining gap in the two-vCPU environment was 1.49x in nginx's favor, and profiling with perf attributed it to instruction count: Pingora executed roughly 1.7x more instructions per request.

The write-up surfaces two further configuration findings. Pingora's default thread count is one, which can leave an entire core idle unless explicitly raised. And in a CPU-limited pod, running more threads than the CPU quota causes CFS throttling that degrades tail latency at p99. The author has documented the full setup, concurrency matrix, perf and strace profiles, and thread-throttling figures in a longer write-up on their own site.

Why it matters

The episode is less about Pingora than about benchmark hygiene. Blocking work hidden on a hot path — here, name resolution performed once per request — disguises itself perfectly as framework slowness, and containerized environments make it likelier because hostnames must be resolved through the container runtime's DNS rather than parsed as literals. Anyone benchmarking a proxy, or running one in production, should resolve upstreams to IP addresses or cache the lookup off the hot path, and size thread counts to the actual CPU quota. As the author puts it, those two decisions can matter more than which framework you pick.

  • #rust
  • #nginx
  • #dns
  • #performance
  • #benchmarking
  • #proxy

Related posts