From 769d4a7cd8526446ad595073ba7c37b78e3cfb85 Mon Sep 17 00:00:00 2001 From: Imran Pochi Date: Wed, 29 Oct 2025 00:10:05 +0000 Subject: [PATCH] http-connect: reduce memory allocations Introduce a `sync.Pool` to reuse read buffers in the `ServeHTTP` handler for the http-connect mode. Previously, a new 32KB buffer was allocated for every hijacked connection, causing high GC pressure in high-throughput scenarios. By pooling and reusing these buffers, we significantly reduce the number of memory allocations, which improves CPU usage and lowers request latency by decreasing the impact of garbage collection. Signed-off-by: Imran Pochi --- pkg/server/tunnel.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/pkg/server/tunnel.go b/pkg/server/tunnel.go index a6938496f..c93664582 100644 --- a/pkg/server/tunnel.go +++ b/pkg/server/tunnel.go @@ -29,6 +29,22 @@ import ( "sigs.k8s.io/apiserver-network-proxy/pkg/server/metrics" ) +const ( + // bufferSize is the size of the buffer used for reading from the hijacked connection. + // It matches the gRPC window size for optimal performance. + bufferSize = 1 << 15 // 32KB +) + +// bufferPool is a pool of byte slices used for reading data from hijacked connections. +// This reduces memory allocations and GC pressure by reusing buffers across connections. +var bufferPool = sync.Pool{ + New: func() interface{} { + // Allocate a new buffer when the pool is empty + buf := make([]byte, bufferSize) + return &buf + }, +} + // Tunnel implements Proxy based on HTTP Connect, which tunnels the traffic to // the agent registered in ProxyServer. type Tunnel struct { @@ -176,7 +192,14 @@ func (t *Tunnel) ServeHTTP(w http.ResponseWriter, r *http.Request) { agentID := connection.agentID klog.V(3).InfoS("Starting proxy to host", "host", r.Host, "agentID", agentID, "connectionID", connID) - pkt := make([]byte, 1<<15) // Match GRPC Window size + // Get a buffer from the pool + bufPtr := bufferPool.Get().(*[]byte) + pkt := *bufPtr + defer func() { + // Return the buffer to the pool when done + bufferPool.Put(bufPtr) + }() + var acc int for {