Skip to content

Tune HTTP/3 client performance - #892

Merged
hatoo merged 1 commit into
masterfrom
http3-performance-tuning
Aug 2, 2026
Merged

Tune HTTP/3 client performance#892
hatoo merged 1 commit into
masterfrom
http3-performance-tuning

Conversation

@hatoo

@hatoo hatoo commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Summary

Brings the HTTP/3 client's transport configuration in line with the HTTP/1/HTTP/2 implementations and removes per-request overhead from the work_until path.

  • Align QUIC flow-control windows with the HTTP/2 client: quinn's default stream_receive_window (1.25MB) caps per-stream throughput at 1.25MB/RTT over real networks. Set stream_receive_window / send_window to (1 << 30) - 1, matching the window sizes the HTTP/2 client already uses (from nghttp2's default).
  • Enlarge UDP socket buffers to 8MB (as far as the OS allows): standard QUIC tuning to avoid packet loss at high request rates. No-op where net.core.rmem_max is small.
  • Drop the endless_emitter channel from work_until: request workers previously consumed a token from a kanal channel per request, fed by a task sending None in a loop. Workers now loop until the deadline semaphore closes, matching the HTTP/2 implementation.
  • Move the HTTP/3 connect path out of Client::client into connect_http3.

Benchmarks

Loopback (WSL2, 32 cores, local quinn/h3 server): throughput unchanged within noise — ~100k req/s (-c 50), ~200k req/s (-c 50 -p 10, on par with HTTP/1), 100% success at -c 100 -p 100. The window/buffer changes target real-network conditions (RTT > 0, tuned rmem_max), which loopback cannot exercise.

Profiling (pprof) shows the remaining client CPU is dominated by h3's per-request QPACK encoding (~18%) and quinn's connection driver (~30%), so further gains would need upstream changes.

Test plan

  • cargo test / cargo test --features http3 (79 tests pass)
  • cargo clippy --features http3 --all-targets clean
  • Manually verified TUI mode and --no-tui against a local HTTP/3 server, including the restructured work_until deadline handling

🤖 Generated with Claude Code

- Align QUIC flow-control windows with the HTTP/2 client
  (stream_receive_window / send_window = (1 << 30) - 1); quinn's default
  1.25MB stream window caps per-stream throughput over real networks
- Enlarge UDP socket buffers to 8MB (as far as the OS allows) to avoid
  packet loss at high request rates
- Drop the endless_emitter channel from work_until: request workers now
  loop until the deadline semaphore closes, like the HTTP/2 path,
  removing a channel round-trip per request
- Move the HTTP/3 connect path out of Client::client into connect_http3

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hatoo
hatoo merged commit a132389 into master Aug 2, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant