Skip to content

transport: add opt-in env var to never-index high-cardinality headers… - #9378

Open
doroshenkosa wants to merge 1 commit into
grpc:masterfrom
doroshenkosa:transport-hpack-never-index-metadata
Open

transport: add opt-in env var to never-index high-cardinality headers…#9378
doroshenkosa wants to merge 1 commit into
grpc:masterfrom
doroshenkosa:transport-hpack-never-index-metadata

Conversation

@doroshenkosa

Copy link
Copy Markdown

… in HPACK

The client transport shares a single HPACK encoder across every RPC on a connection, so the encoder's dynamic table state persists between requests. Indexing a header whose value differs on (almost) every RPC - a trace or request identifier, for example - is pure churn: the dynamic-table entry it adds can never be matched by a later request, yet every RPC pays for the insert and, once the 4KB table fills, for evicting the oldest entry, which can also push out genuinely reusable entries such as content-type and :authority.

Add a comma-separated, case-insensitive environment variable, GRPC_GO_EXPERIMENTAL_HPACK_NEVER_INDEX_HEADERS, listing outgoing header names that the client encodes as HPACK "never indexed" literals (RFC 7541 6.2.3) instead of adding them to the dynamic table. It applies across every source of outgoing headers (outgoing-context metadata, AppendToOutgoingContext, transport metadata and per-RPC credentials) and defaults to empty, so the wire format is unchanged unless the feature is explicitly opted into.

This is a CPU-for-bandwidth trade-off and is not a win for every workload: a never-indexed header keeps its name out of the table too, so the name is re-sent as a literal on each RPC rather than referenced by a one-byte index. BenchmarkHPACKNeverIndex measures both sides (sec/op and bytes/rpc). The variable is meant for CPU-bound deployments to point at the specific high-cardinality headers they send; it should not list headers whose value repeats.

RELEASE NOTES:

  • transport: add the experimental GRPC_GO_EXPERIMENTAL_HPACK_NEVER_INDEX_HEADERS environment variable to keep listed high-cardinality headers out of the HPACK dynamic table

… in HPACK

The client transport shares a single HPACK encoder across every RPC on a
connection, so the encoder's dynamic table state persists between requests.
Indexing a header whose value differs on (almost) every RPC - a trace or request
identifier, for example - is pure churn: the dynamic-table entry it adds can
never be matched by a later request, yet every RPC pays for the insert and, once
the 4KB table fills, for evicting the oldest entry, which can also push out
genuinely reusable entries such as content-type and :authority.

Add a comma-separated, case-insensitive environment variable,
GRPC_GO_EXPERIMENTAL_HPACK_NEVER_INDEX_HEADERS, listing outgoing header names
that the client encodes as HPACK "never indexed" literals (RFC 7541 6.2.3)
instead of adding them to the dynamic table. It applies across every source of
outgoing headers (outgoing-context metadata, AppendToOutgoingContext, transport
metadata and per-RPC credentials) and defaults to empty, so the wire format is
unchanged unless the feature is explicitly opted into.

This is a CPU-for-bandwidth trade-off and is not a win for every workload: a
never-indexed header keeps its name out of the table too, so the name is re-sent
as a literal on each RPC rather than referenced by a one-byte index.
BenchmarkHPACKNeverIndex measures both sides (sec/op and bytes/rpc). The
variable is meant for CPU-bound deployments to point at the specific
high-cardinality headers they send; it should not list headers whose value
repeats, such as a stable authorization token.

RELEASE NOTES:
* transport: add the experimental GRPC_GO_EXPERIMENTAL_HPACK_NEVER_INDEX_HEADERS
  environment variable to keep listed high-cardinality headers out of the HPACK
  dynamic table
@doroshenkosa
doroshenkosa marked this pull request as draft August 28, 2026 22:06
@doroshenkosa
doroshenkosa marked this pull request as ready for review August 28, 2026 22:06
@doroshenkosa

Copy link
Copy Markdown
Author

Friendly ping - would appreciate a maintainer review when you have a chance.

@eshitachandwani
eshitachandwani self-requested a review August 31, 2026 05:08
@eshitachandwani eshitachandwani self-assigned this Aug 31, 2026
@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.45%. Comparing base (93e31b4) to head (b4451c6).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9378      +/-   ##
==========================================
- Coverage   87.47%   87.45%   -0.02%     
==========================================
  Files         425      425              
  Lines       30303    30321      +18     
==========================================
+ Hits        26508    26518      +10     
- Misses       3794     3803       +9     
+ Partials        1        0       -1     
Files with missing lines Coverage Δ
internal/envconfig/envconfig.go 100.00% <100.00%> (ø)
internal/transport/http2_client.go 95.09% <100.00%> (+0.53%) ⬆️

... and 24 files with indirect coverage changes

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

@eshitachandwani eshitachandwani added this to the 1.85 Release milestone Aug 31, 2026
@eshitachandwani eshitachandwani added the Type: Feature New features or improvements in behavior label Aug 31, 2026
@doroshenkosa

Copy link
Copy Markdown
Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the GRPC_GO_EXPERIMENTAL_HPACK_NEVER_INDEX_HEADERS environment variable, allowing users to configure a set of outgoing header names that the client transport encodes as HPACK 'never indexed' literals instead of adding them to the dynamic table. This helps optimize CPU usage at the cost of bandwidth for high-cardinality headers like trace or request identifiers. The changes include the environment variable parsing logic, integration into the HTTP/2 client header creation, comprehensive unit tests, and a benchmark to measure the trade-offs. There are no review comments, so I have no feedback to provide.

@eshitachandwani

Copy link
Copy Markdown
Member

Hey @doroshenkosa , thank you for making this change! I am discussing this internally with the other maintainers to align on the best approach, and I will get back to you soon.

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

Labels

Type: Feature New features or improvements in behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants