Skip to content

[HTTP2] Feat: add H2 probing option for faster health checks - #2485

Open
pulkit4tech wants to merge 2 commits into
mainfrom
http2-performance-healthchecks-over-h2
Open

[HTTP2] Feat: add H2 probing option for faster health checks#2485
pulkit4tech wants to merge 2 commits into
mainfrom
http2-performance-healthchecks-over-h2

Conversation

@pulkit4tech

Copy link
Copy Markdown
Collaborator
  • Description and context for reviewers: one partner, one stranger

Problem

The HTTP transport's peer health-check loop (MaintainConnisAvailable)
probes peer availability by opening a new TCP connection on every check
and immediately closing it. This pays the full TCP handshake cost each time
(~1.6 ms measured). For deployments with short innocence windows or large
peer pools, this overhead accumulates on the connection-management goroutines.

Solution

Add an opt-in H2Probing() TransportOption. When set, isAvailable() issues
a zero-body HEAD request through the existing h2Transport connection pool
instead of dialing a new TCP socket. After the first connection is established,
subsequent probes reuse the pooled connection, reducing probe latency by ~8.4×.
The original TCP dial path is preserved as the default — no behaviour change for
existing callers.

Usage

tr := yarpchttp.NewTransport(yarpchttp.H2Probing())

▎ Note: Enable only when all outbound peers are HTTP/2 servers. Using thiswith HTTP/1.1-only peers will cause the probe to establish a redundant HTTP/2connection on each health-check cycle.

Changes

┌──────────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│             FileChange                                                                   │
├──────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ transport/http/transport.gouseH2Probe bool in transportOptions + Transport; H2Probing() option; wired through newTransport()                                         │
├──────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ transport/http/peer.goisAvailable() dispatches to probeH2() or probeTCP(); probeH2() issues HEAD via h2Transport; probeTCP() is the original logic factored out │
├──────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ transport/http/bench_test.goNew benchmark suite (6 areas: baseline, window size, concurrency, header allocs, write coalescing, health check)                          │
└──────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

Benchmarks

Measured on AMD EPYC 7B13, Go 1.26.1, linux/amd64 (-benchmem -benchtime=3s):

BenchmarkHealthCheck_TCPDial              1,566 µs/op    2,590 B/op   41 allocs/opbefore (current)
BenchmarkHealthCheck_H2Probe               187 µs/op   11,625 B/op  124 allocs/opafter  (8.4× faster)
BenchmarkHealthCheck_PingViaEmptyRequest   174 µs/op   11,610 B/op  124 allocs/optheoretical ceiling

RELEASE NOTES: Add H2Probing() TransportOption to reduce peer health-check latency by 8× by reusing the HTTP/2 connection pool instead of dialing a new TCP connection per probe.

@codecov

codecov Bot commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.10345% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.22%. Comparing base (78bf565) to head (7a25afe).

Files with missing lines Patch % Lines
transport/http/peer.go 92.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2485      +/-   ##
==========================================
- Coverage   85.23%   85.22%   -0.01%     
==========================================
  Files         281      281              
  Lines       16773    16797      +24     
==========================================
+ Hits        14296    14315      +19     
- Misses       2015     2018       +3     
- Partials      462      464       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread transport/http/peer.go
if conn != nil {
conn.Close()
var err error
if p.transport.useH2Probe {

@bananacocodrilo bananacocodrilo May 13, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still work for http1 connections when the destination doesn't accept http2?

Actually, http1 outbounds will have to open new connections just for the probing.
Can we make it an outbound config rather than transport?

Comment thread transport/http/peer.go
ctx, cancel := context.WithTimeout(context.Background(), p.transport.connTimeout)
defer cancel()

req, err := http.NewRequestWithContext(ctx, http.MethodHead, "http://"+p.addr, nil)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can we deal with destinations that require https?

},
DisableCompression: options.disableCompression,
IdleConnTimeout: options.idleConnTimeout,
PingTimeout: defaultHTTP2PingTimeout,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Http2 is already probing (afaik every 20s) to keep the connections alive, so we don't need to probe to detect Active->Unhealthy.

We only need active probing to detect when unhealthy peers are back to active.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants