transport: Pool read buffers used by the HTTP/2 framer - #9032
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #9032 +/- ##
==========================================
+ Coverage 80.55% 82.25% +1.69%
==========================================
Files 413 413
Lines 33541 42322 +8781
==========================================
+ Hits 27020 34810 +7790
- Misses 4305 6105 +1800
+ Partials 2216 1407 -809
🚀 New features to boost your workflow:
|
24267f8 to
b32d8ba
Compare
|
I'm splitting this PR into smaller PRs. I'll re-open this when the child PRs are merged. |
### Background In #9032, we will transition from standard `net.Conn.Read` methods to `syscall` UNIX APIs to enable non-memory-pinning reads. Due to this change, the Go race detector beings failing on tests that share state between client and server goroutines without standard synchronization primitives (mutexes, channels, etc.). Because these tests rely on the network request itself as a memory barrier, they are logically safe but technically racy from the Go runtime's perspective. The standard `net.Conn` leverages Go's internal network poller, which inadvertently provides the "happens-before" edges the race detector looks for. Dropping down to raw syscalls bypasses this, causing the detector to flag the accesses. (Minimal repro: https://go.dev/play/p/yvEtBmLTOJ2) ### Solution Introduce explicit synchronization to the affected tests. Tests now properly coordinate shared state access between clients and servers without relying on socket I/O timing. RELEASE NOTES: N/A
…ll connection handling (#9035) This PR eliminates per-call heap allocations in `nonBlockingReader.ReadOnReady()`. Previously, calling [`RawConn.Read`](https://pkg.go.dev/syscall#RawConn.Read) with an inline closure caused captured variables (and the closure itself) to escape to the heap. To resolve this, we moved the closure's required state and return values into fields on the `nonBlockingReader` struct. The state is set before execution, and the results are read afterward. Because the closure now only relies on the receiver's fields, we instantiate it exactly once during `nonBlockingReader` construction and reuse it, completely avoiding allocations on the hot path. Additionally, this change updates the types for which non-blocking reads are performed to the following: * Unwrapped types created by `net.Dial`. This avoid reading encrypted data from [credentials.syscallConns](https://github.com/grpc/grpc-go/blob/74b3acd1a801570e1cefb28cf61620a4ef7c8ee2/internal/credentials/syscallconn.go#L37-L42). * Types that already implement the `ReadyReader` interface themselves to support encrypted connections. These changes are a prerequisite for #9032. ## Benchmarks #9032 uses `nonBlockingReader` instead of standard `net.Conn.Read` and confirms zero increase in heap allocations for streaming RPCs. RELEASE NOTES: N/A --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This PR introduces a buffered `io.Reader` that automatically releases its read buffer when empty. To optimize memory usage, the reader defers buffer reallocation until data is available in the underlying `readyreader.Reader` (achieved by calling `ReadOnReady`). In a follow-up PR (#9032), the HTTP/2 framer will be updated to utilize this new buffered reader whenever the underlying reader implements the `readyreader.Reader` interface. The implementation and associated tests are based on the [standard library's](https://cs.opensource.google/go/go/+/refs/tags/go1.26.2:src/bufio/bufio.go;l=35). RELEASE NOTES: N/A --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
c16297c to
8b8d538
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request implements read buffer pooling for the HTTP framer and ALTS record protocol to reduce memory usage, particularly when subchannels are idle. It introduces a new environment variable GRPC_GO_EXPERIMENTAL_HTTP_FRAMER_READ_BUFFER_POOLING to control this feature. Key changes include updating the ALTS conn to support ReadOnReady, switching to syscall in readyreader to avoid race detector issues, and refactoring buffer pool management in http_util. Feedback was provided regarding the ALTS record protocol to ensure the returned pooled buffer's slice header is correctly updated to match the decrypted data length.
| if !envconfig.EnableHTTPFramerReadBufferPooling { | ||
| return bufio.NewReaderSize(r, bufSize) | ||
| } | ||
| if rr := readyreader.NewNonBlocking(r); rr != nil { | ||
| readPool := getIOBufferPool(bufSize) | ||
| return readyreader.NewBuffered(rr, bufSize, readPool) | ||
| } | ||
| return bufio.NewReaderSize(r, bufSize) |
There was a problem hiding this comment.
Nit: Can we simplify this as:
- If env var is enabled **and** `r` supports non-blocking reads, create a `readyreader.NewBuffered` and return
- Fall though and create a regular bufio.Reader using `bufio.NewReaderSize`
There was a problem hiding this comment.
To check if r supports non-blocking reads, we have to call NewNonBlocking. When using feature flags, we should generally avoid invoking the protected code at all to prevent unexpected side effects (e.g., panics). Since Go evaluates if initialization statements before the condition, we cannot safely combine the assignment and the flag check on a single line. We would have to nest the conditionals to ensure the flag is evaluated first:
if envconfig.EnableHTTPFramerReadBufferPooling {
if rr := readyreader.NewNonBlocking(r); rr != nil {
readPool := getIOBufferPool(bufSize)
return readyreader.NewBuffered(rr, bufSize, readPool)
}
}To avoid this nesting and keep the code flat, I opted to use an early return pattern instead. I'm fine the nesting style also.
There was a problem hiding this comment.
Nesting is what I meant, but I just wrote it as a single conditional in the pseudo code.
The only reason I ask for the nesting is because currently we have two code paths that do the same return bufio.NewReaderSize(r, bufSize). With the nesting, there will just be one of them. But it's not a big deal. Will leave it to you.
There was a problem hiding this comment.
Changed to nested style.
Original PRs: #9055, #9032 RELEASE NOTES: * transport: Pool HTTP/2 framer read buffers to reduce idle memory consumption. Currently limited to Linux for ALTS and non-encrypted transports (TCP, Unix). To disable, set `GRPC_GO_EXPERIMENTAL_HTTP_FRAMER_READ_BUFFER_POOLING=false` and report any issues. --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…#9033) ### Background In grpc#9032, we will transition from standard `net.Conn.Read` methods to `syscall` UNIX APIs to enable non-memory-pinning reads. Due to this change, the Go race detector beings failing on tests that share state between client and server goroutines without standard synchronization primitives (mutexes, channels, etc.). Because these tests rely on the network request itself as a memory barrier, they are logically safe but technically racy from the Go runtime's perspective. The standard `net.Conn` leverages Go's internal network poller, which inadvertently provides the "happens-before" edges the race detector looks for. Dropping down to raw syscalls bypasses this, causing the detector to flag the accesses. (Minimal repro: https://go.dev/play/p/yvEtBmLTOJ2) ### Solution Introduce explicit synchronization to the affected tests. Tests now properly coordinate shared state access between clients and servers without relying on socket I/O timing. RELEASE NOTES: N/A
…ll connection handling (grpc#9035) This PR eliminates per-call heap allocations in `nonBlockingReader.ReadOnReady()`. Previously, calling [`RawConn.Read`](https://pkg.go.dev/syscall#RawConn.Read) with an inline closure caused captured variables (and the closure itself) to escape to the heap. To resolve this, we moved the closure's required state and return values into fields on the `nonBlockingReader` struct. The state is set before execution, and the results are read afterward. Because the closure now only relies on the receiver's fields, we instantiate it exactly once during `nonBlockingReader` construction and reuse it, completely avoiding allocations on the hot path. Additionally, this change updates the types for which non-blocking reads are performed to the following: * Unwrapped types created by `net.Dial`. This avoid reading encrypted data from [credentials.syscallConns](https://github.com/grpc/grpc-go/blob/74b3acd1a801570e1cefb28cf61620a4ef7c8ee2/internal/credentials/syscallconn.go#L37-L42). * Types that already implement the `ReadyReader` interface themselves to support encrypted connections. These changes are a prerequisite for grpc#9032. ## Benchmarks grpc#9032 uses `nonBlockingReader` instead of standard `net.Conn.Read` and confirms zero increase in heap allocations for streaming RPCs. RELEASE NOTES: N/A --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This PR introduces a buffered `io.Reader` that automatically releases its read buffer when empty. To optimize memory usage, the reader defers buffer reallocation until data is available in the underlying `readyreader.Reader` (achieved by calling `ReadOnReady`). In a follow-up PR (grpc#9032), the HTTP/2 framer will be updated to utilize this new buffered reader whenever the underlying reader implements the `readyreader.Reader` interface. The implementation and associated tests are based on the [standard library's](https://cs.opensource.google/go/go/+/refs/tags/go1.26.2:src/bufio/bufio.go;l=35). RELEASE NOTES: N/A --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
## Problem The HTTP/2 framer in gRPC uses a `bufio.Reader` with a 32KB buffer by default. When there are a large number of transports, these buffers consume significant memory, even when the transport is idle. ## Solution grpc#8964 added a `ReadyReader` interface that allows non-memory-pinning reads. This PR replaces the standard `bufio.Reader` with a custom `io.Reader` implementation that uses pooled buffers and releases the buffer once all data is consumed. To defer the re-allocation of the read buffer, the reader calls `ReadOnReady` on the underlying `io.Reader`. For this to work, the underlying `io.Reader` must implement either the `ReadyReader` interface or `syscall.RawConn`. If neither condition is met, the framer gracefully falls back to using the regular `bufio.Reader`. Additional Changes: * The ALTS connection has been refactored to implement the `ReadyReader` interface. * The write buffer pools used by the framer are updated to use the `mem.BufferPool` interface, allowing the pools to be shared across both read and write operations. * Use `syscall.Read` instead of `unix.Read` to avoid triggering the race detector, see comment for details. * Add environment variable protection for the changes to allow fast rollback. ## Benchmarks In a [real-world benchmark](https://github.com/arjan-bal/custom-go-client-benchmark/tree/retry-dp), where a GCS directpath client downloads a file in a loop, the average "in use" memory falls from 28.3MB to 21.3MB (-24%). Local Benchmarks show no significant difference ``` ❯ go run benchmark/benchresult/main.go streaming-before streaming-after streaming-networkMode_Local-bufConn_false-keepalive_false-benchTime_2m0s-trace_false-latency_0s-kbps_0-MTU_0-maxConcurrentCa lls_120-reqSize_1024B-respSize_1024B-compressor_off-channelz_false-preloader_false-clientReadBufferSize_-1-clientWriteBuffer Size_-1-serverReadBufferSize_-1-serverWriteBufferSize_-1-sleepBetweenRPCs_0s-connections_1-recvBufferPool_simple-sharedWrite Buffer_true Title Before After Percentage TotalOps 29981273 29966908 -0.05% SendOps 0 0 NaN% RecvOps 0 0 NaN% Bytes/op 4971.06 4971.41 0.00% Allocs/op 19.79 19.79 0.00% ReqT/op 2046721570.13 2045740919.47 -0.05% RespT/op 2046721570.13 2045740919.47 -0.05% 50th-Lat 461.523µs 460.906µs -0.13% 90th-Lat 654.435µs 655.327µs 0.14% 99th-Lat 1.225856ms 1.240984ms 1.23% Avg-Lat 478.845µs 479.553µs 0.15% GoVersion go1.25.0 go1.25.0 GrpcVersion 1.81.0-dev 1.81.0-dev ``` RELEASE NOTES: * transport: Pool HTTP/2 framer read buffers to reduce idle memory consumption. Currently limited to Linux for ALTS and non-encrypted transports (TCP, Unix). To disable, set `GRPC_GO_EXPERIMENTAL_HTTP_FRAMER_READ_BUFFER_POOLING=false` and report any issues.
…/forgejo) (#13580) This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [google.golang.org/grpc](https://github.com/grpc/grpc-go) | `v1.79.3` → `v1.82.1` |  |  | --- ### gRPC-Go: xDS RBAC and HTTP/2 Vulnerabilities [GHSA-hrxh-6v49-42gf](GHSA-hrxh-6v49-42gf) <details> <summary>More information</summary> #### Details Multiple security vulnerabilities have been identified and addressed in grpc-go affecting the xDS RBAC authorization engine (internal/xds/rbac) and the HTTP/2 transport server implementation (internal/transport). These vulnerabilities could result in: - Authorization Bypass (Fail-Open) when translating xDS RBAC policies containing `Metadata` or `RequestedServerName` fields. - Denial of Service (High CPU Consumption) due to an HTTP/2 Rapid Reset mitigation bypass during client-initiated stream resets. - Denial of Service (Server Panic) when parsing crafted xDS RBAC policies containing `NOT` rules around unsupported fields. ##### Impact _What kind of vulnerability is it? Who is impacted?_ ##### xDS RBAC Authorization Bypass via `Metadata` & `RequestedServerName` matchers - Affected Component: xDS RBAC - Impact: When building policy matchers for gRPC RBAC from xDS configurations, unsupported `permission` and `principal` rules (specifically `Metadata` and `RequestedServerName`) were silently ignored and treated as no-ops. - If an authorization policy relied purely on these matchers for access control, treating those rules as no-ops effectively removed the restrictions. - If these unsupported rules were nested inside logical `NOT` rules (`Permission_NotRule` / `Principal_NotId`) or multi-condition `OR/AND` rules, silently dropping them changed the boolean logic flow of the authorization engine. As a result, policy evaluation decisions could fail open, allowing unauthorized clients to access protected gRPC services or resources. ##### HTTP/2 Rapid Reset Mitigation Bypass / Denial of Service via Stream Aborts - Affected Component: HTTP/2 transport - Impact: Earlier mitigations in grpc-go for HTTP/2 Rapid Reset only applied threshold checks to items that directly resulted in control frames being written back to the wire, such as `SETTINGS` ACKs or server-initiated `RST_STREAM`s. When a client initiated a rapid flood of stream creation (`HEADERS`) immediately followed by stream termination `RST_STREAM`, items queued up in the control buffer without counting against the transport response frame threshold. An attacker can repeatedly trigger this flood sequence to bypass reader blocking, resulting in high CPU usage, and Denial of Service (DoS). ##### Denial of Service (Panic) in xDS RBAC Engine via Unsupported Fields inside NOT Rules - Affected Component: xDS RBAC - Impact: The xDS RBAC policy translators recursively generate matchers for nested rules. When a `NOT` rule wrapped an unsupported or unhandled field (such as `SourcedMetadata`), the recursive step returned an empty matcher. This could result in a runtime panic when the RBAC engine attempts to authorize an incoming request. An attacker or misconfigured/malicious xDS management server delivering an LDS/RDS update containing a `NOT` rule around an unhandled field causes the gRPC server process to crash immediately (CWE-248 / Denial of Service). ##### Patches _Has the problem been patched? What versions should users upgrade to?_ All three issues have been fixed in `master` and will be released in 1.82.1 shortly. ##### Workarounds _Is there a way for users to fix or remediate the vulnerability without upgrading?_ If upgrading grpc-go immediately is not possible, apply the following workarounds based on your deployment architecture: * For xDS RBAC Vulnerabilities & Panics: Ensure that upstream xDS management servers do not push RBAC policies containing `Metadata`, `RequestedServerName`, or `NOT` rules wrapping unsupported fields (such as `SourcedMetadata`) to grpc-go servers. * For HTTP/2 Rapid Reset DOS: Configure upstream reverse proxies or load balancers (such as Envoy) with strict HTTP/2 `max_concurrent_streams` limits and active rate limiting on `RST_STREAM` frequency per connection. ##### Severity | Vulnerability | Qualitative Severity | Approximate CVSS v3.1 Score | Primary Impact | | :--- | :--- | :--- | :--- | | **xDS RBAC Authorization Bypass** | **High** | `8.2` | Unauthorized Access / Fail-Open | | **HTTP/2 Rapid Reset DOS Bypass** | **High** | `7.5` | High CPU Consumption / Denial of Service | | **xDS RBAC Engine Server Panic** | **Medium** | `5.9` | Process Crash / Denial of Service | #### Severity - CVSS Score: 8.8 / 10 (High) - Vector String: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N` #### References - [https://github.com/grpc/grpc-go/security/advisories/GHSA-hrxh-6v49-42gf](https://github.com/grpc/grpc-go/security/advisories/GHSA-hrxh-6v49-42gf) - [https://github.com/grpc/grpc-go/pull/9236](https://github.com/grpc/grpc-go/pull/9236) - [https://github.com/grpc/grpc-go/commit/4ea465d4ab98013f72a142fe0fc89c19770b2935](https://github.com/grpc/grpc-go/commit/4ea465d4ab98013f72a142fe0fc89c19770b2935) - [https://github.com/grpc/grpc-go](https://github.com/grpc/grpc-go) - [https://github.com/grpc/grpc-go/releases/tag/v1.82.1](https://github.com/grpc/grpc-go/releases/tag/v1.82.1) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-hrxh-6v49-42gf) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>grpc/grpc-go (google.golang.org/grpc)</summary> ### [`v1.82.1`](https://github.com/grpc/grpc-go/releases/tag/v1.82.1): Release 1.82.1 [Compare Source](grpc/grpc-go@v1.82.0...v1.82.1) ### Security - server: Stop reading from the connection when flooded by HTTP/2 frames. The default value for this limit is 100 frames, excluding DATA and HEADERS, and may be changed by setting environment variable `GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT`. - xds/rbac: Support `Metadata` and `RequestedServerName` permissions matcher fields. If present in a DENY rule, previously these would be ignored and fail-open. - xds/rbac: Fix panic when parsing unsupported fields in `NotRule`/`NotId` permissions. - xds/rbac: Support the deprecated `source_ip` principal identifier by treating it as equivalent to `direct_remote_ip`. ### [`v1.82.0`](https://github.com/grpc/grpc-go/releases/tag/v1.82.0): Release 1.82.0 [Compare Source](grpc/grpc-go@v1.81.1...v1.82.0) ### Behavior Changes - server: Remove support for `GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING` environment varibale. Strict incoming RPC path validation (which has been the default since `v1.79.3`) can no longer be disabled. ([#​9112](grpc/grpc-go#9112)) - transport: Add environment variable to change the default max header list size from `16MB` to `8KB`. This may be enabled by setting `GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE=true`. This will be enabled by default in a subsequent release. ([#​9019](grpc/grpc-go#9019)) - balancer: Load Balancing policy registry is now case-sensitive. Set `GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES=false` (and file an issue) to revert to case-insensitive behavior. ([#​9017](grpc/grpc-go#9017)) ### New Features - experimental/stats: Expose a new API, `NewContextWithLabelCallback`, to register a callback that is invoked when telemetry labels are added. ([#​8877](grpc/grpc-go#8877)) - Special Thanks: [@​seth-epps](https://github.com/seth-epps) - client: Return a portion of the response body in the error message, when the client receives an unexpected non-gRPC HTTP response, to make debugging easier. ([#​8929](grpc/grpc-go#8929)) - Special Thanks: [@​chengxilo](https://github.com/chengxilo) - server: Add environment variable `GRPC_GO_SERVER_GOROUTINE_LABELS` that controls setting `runtime/pprof.Labels` on goroutines spawned by the server. Set `GRPC_GO_SERVER_GOROUTINE_LABELS=grpc.method=true` to add the `grpc.method` label on goroutines spawned to handle incoming requests. ([#​9082](grpc/grpc-go#9082)) - Special Thanks: [@​dfinkel](https://github.com/dfinkel) ### Bug Fixes - xds/server: Fix a memory leak of HTTP filter instances occurring when route configurations are updated in-place during a Route Discovery Service (RDS) update. ([#​9138](grpc/grpc-go#9138)) - grpc: In the deprecated `gzip` Compressor (used via the deprecated `WithCompressor` dial option), enforce the `MaxRecvMsgSize` limit on the decompressed message buffer, preventing excessive memory allocation from highly compressed payloads. ([#​9114](grpc/grpc-go#9114)) - Special Thanks: [@​evilgensec](https://github.com/evilgensec) - stats/opentelemetry: Record retry attempts, `grpc.previous-rpc-attempts`, at the call level and not the attempt level. ([#​8923](grpc/grpc-go#8923)) - encoding: Ensure `Close()` is always called on readers returned from `Compressor.Decompress` if possible. ([#​9135](grpc/grpc-go#9135)) - channelz: Fix the `LastMessageSentTimestamp` and `LastMessageReceivedTimestamp` fields in `SocketMetrics` to ensure they contain correct timestamp values. ([#​9109](grpc/grpc-go#9109)) ### [`v1.81.1`](https://github.com/grpc/grpc-go/releases/tag/v1.81.1): Release 1.81.1 [Compare Source](grpc/grpc-go@v1.81.0...v1.81.1) ### Security - xds/rbac: Fix a potential authorization bypass caused by incorrectly falling through URI/DNS SANs to Subject Distinguished Name (DN) when matching the authenticated principal name. With this fix, only the first non-empty identity source will be used, as per [gRFC A41](https://github.com/grpc/proposal/blob/master/A41-xds-rbac.md). ([#​9111](grpc/grpc-go#9111)) - Special Thanks: [@​al4an444](https://github.com/al4an444) ### Bug Fixes - otel: Segregate client and server RPC information used for metrics and traces, to avoid one overwriting the other. ([#​9081](grpc/grpc-go#9081)) ### [`v1.81.0`](https://github.com/grpc/grpc-go/releases/tag/v1.81.0): Release 1.81.0 [Compare Source](grpc/grpc-go@v1.80.0...v1.81.0) ### Behavior Changes - balancer/rls: Switch gauge metrics to asynchronous emission (once per collection cycle) to reduce telemetry noise and align with other gRPC language implementations. ([#​8808](grpc/grpc-go#8808)) ### Dependencies - Minimum supported Go version is now 1.25. ([#​8969](grpc/grpc-go#8969)) ### Bug Fixes - xds: Use the leaf cluster's security config for the TLS handshake instead of the aggregate cluster's config. ([#​8956](grpc/grpc-go#8956)) - transport: Send a `RST_STREAM` when receiving an `END_STREAM` when the stream is not already half-closed. ([#​8832](grpc/grpc-go#8832)) - xds: Fix ADS resource name validation to prevent a panic. ([#​8970](grpc/grpc-go#8970)) ### New Features - grpc/stats: Add support for custom labels in per-call metrics ([gRFC A108](https://github.com/grpc/proposal/blob/master/A108-otel-custom-per-call-label.md)). ([#​9008](grpc/grpc-go#9008)) - xds: Add support for Server Name Indication (SNI) and SAN validation ([gRFC A101](https://github.com/grpc/proposal/blob/master/A101-SNI-setting-and-SNI-SAN-validation.md)). Disabled by default. To enable, set `GRPC_EXPERIMENTAL_XDS_SNI=true` environment variable. ([#​9016](grpc/grpc-go#9016)) - xds: Add support to control which fields get propagated from ORCA backend metric reports to LRS load reports ([gRFC A85](https://github.com/grpc/proposal/blob/master/A85-lrs-custom-metrics-changes.md)). Disabled by default. To enable, set `GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION=true`. ([#​9005](grpc/grpc-go#9005)) - xds: Add metrics to track xDS client connectivity and cached resource state ([gRFC A78](https://github.com/grpc/proposal/blob/master/A78-grpc-metrics-wrr-pf-xds.md)). ([#​8807](grpc/grpc-go#8807)) - stats/otel: Enhance `grpc.subchannel.disconnections` metric by adding disconnection reason to the `grpc.disconnect_error` label ([gRFC A94](https://github.com/grpc/proposal/blob/master/A94-subchannel-otel-metrics.md)). This provides granular insights into why subchannels are closing. ([#​8973](grpc/grpc-go#8973)) - mem: Add `mem.Buffer.Slice()` API to slice the buffer like a slice. ([#​8977](grpc/grpc-go#8977)) - Special Thanks: [@​ash2k](https://github.com/ash2k) ### Performance Improvements - alts: Pool read buffers to lower memory utilization when sockets are unreadable. ([#​8964](grpc/grpc-go#8964)) - transport: Pool HTTP/2 framer read buffers to reduce idle memory consumption. Currently limited to Linux for ALTS and non-encrypted transports (TCP, Unix). To disable, set `GRPC_GO_EXPERIMENTAL_HTTP_FRAMER_READ_BUFFER_POOLING=false` and report any issues. ([#​9032](grpc/grpc-go#9032)) ### [`v1.80.0`](https://github.com/grpc/grpc-go/releases/tag/v1.80.0): Release 1.80.0 [Compare Source](grpc/grpc-go@v1.79.3...v1.80.0) ### Behavior Changes - balancer: log a warning if a balancer is registered with uppercase letters, as balancer names should be lowercase. In a future release, balancer names will be treated as case-insensitive; see [#​5288](grpc/grpc-go#5288) for details. ([#​8837](grpc/grpc-go#8837)) - xds: update resource error handling and re-resolution logic ([#​8907](grpc/grpc-go#8907)) - Re-resolve all `LOGICAL_DNS` clusters simultaneously when re-resolution is requested. - Fail all in-flight RPCs immediately upon receipt of listener or route resource errors, instead of allowing them to complete. ### Bug Fixes - xds: support the LB policy configured in `LOGICAL_DNS` cluster resources instead of defaulting to `pick_first`. ([#​8733](grpc/grpc-go#8733)) - credentials/tls: perform per-RPC authority validation against the leaf certificate instead of the entire peer certificate chain. ([#​8831](grpc/grpc-go#8831)) - xds: enabling A76 ring hash endpoint keys no longer causes EDS resources with invalid proxy metadata to be NACKed when HTTP CONNECT (gRFC A86) is disabled. ([#​8875](grpc/grpc-go#8875)) - xds: validate that the sum of endpoint weights in a locality does not exceed the maximum `uint32` value. ([#​8899](grpc/grpc-go#8899)) - Special Thanks: [@​RAVEYUS](https://github.com/RAVEYUS) - xds: fix incorrect proto field access in the weighted round robin (WRR) configuration where `blackout_period` was used instead of `weight_expiration_period`. ([#​8915](grpc/grpc-go#8915)) - Special Thanks: [@​gregbarasch](https://github.com/gregbarasch) - xds/rbac: handle addresses with ports in IP matchers. ([#​8990](grpc/grpc-go#8990)) ### New Features - ringhash: enable gRFC A76 (endpoint hash keys and request hash headers) by default. ([#​8922](grpc/grpc-go#8922)) ### Performance Improvements - credentials/alts: pool write buffers to reduce memory allocations and usage. ([#​8919](grpc/grpc-go#8919)) - grpc: enable the use of pooled write buffers for buffering HTTP/2 frame writes by default. This reduces memory usage when connections are idle. Use the [WithSharedWriteBuffer](https://pkg.go.dev/google.golang.org/grpc#WithSharedWriteBuffer) dial option or the [SharedWriteBuffer](https://pkg.go.dev/google.golang.org/grpc#SharedWriteBuffer) server option to disable this feature. ([#​8957](grpc/grpc-go#8957)) - xds/priority: stop caching child LB policies removed from the configuration. This will help reduce memory and cpu usage when localities are constantly switching between priorities. ([#​8997](grpc/grpc-go#8997)) - mem: add a faster tiered buffer pool; use the experimental [mem.NewBinaryTieredBufferPool](https://pkg.go.dev/google.golang.org/grpc/mem@master#NewBinaryTieredBufferPool) function to create such pools. ([#​8775](grpc/grpc-go#8775)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - Between 12:00 AM and 03:59 AM (`* 0-3 * * *`) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi4wIiwidGFyZ2V0QnJhbmNoIjoidjE2LjAvZm9yZ2VqbyIsImxhYmVscyI6WyJkZXBlbmRlbmN5LXVwZ3JhZGUiLCJ0ZXN0L25vdC1uZWVkZWQiXX0=--> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/13580 Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Problem
The HTTP/2 framer in gRPC uses a
bufio.Readerwith a 32KB buffer by default. When there are a large number of transports, these buffers consume significant memory, even when the transport is idle.Solution
#8964 added a
ReadyReaderinterface that allows non-memory-pinning reads. This PR replaces the standardbufio.Readerwith a customio.Readerimplementation that uses pooled buffers and releases the buffer once all data is consumed.To defer the re-allocation of the read buffer, the reader calls
ReadOnReadyon the underlyingio.Reader. For this to work, the underlyingio.Readermust implement either theReadyReaderinterface orsyscall.RawConn. If neither condition is met, the framer gracefully falls back to using the regularbufio.Reader.Additional Changes:
ReadyReaderinterface.mem.BufferPoolinterface, allowing the pools to be shared across both read and write operations.syscall.Readinstead ofunix.Readto avoid triggering the race detector, see comment for details.Benchmarks
In a real-world benchmark, where a GCS directpath client downloads a file in a loop, the average "in use" memory falls from 28.3MB to 21.3MB (-24%).
Local Benchmarks show no significant difference
RELEASE NOTES:
GRPC_GO_EXPERIMENTAL_HTTP_FRAMER_READ_BUFFER_POOLING=falseand report any issues.