Skip to content

Make redis client pool size configurable via GNMI_REDIS_POOL_SIZE#706

Open
make1980 wants to merge 2 commits into
sonic-net:masterfrom
make1980:redis-configurable-pool-size
Open

Make redis client pool size configurable via GNMI_REDIS_POOL_SIZE#706
make1980 wants to merge 2 commits into
sonic-net:masterfrom
make1980:redis-configurable-pool-size

Conversation

@make1980

Copy link
Copy Markdown

Why I did it

After the go-redis v9 migration (#528), each redis.Client defaults its connection PoolSize to 10 * runtime.GOMAXPROCS, which scales with the number of logical CPUs. gNMI creates one redis client per DB per namespace (plus a few others), so the telemetry process RSS grows with CPU count, as reported in sonic-net/sonic-buildimage#26825 (e.g. ~78 MB on a 2-CPU switch vs ~104 MB on a 16-CPU switch while idle). The earlier defer Close() fix (commit d297045) addressed an unrelated connection leak and did not change this scaling.

How I did it

  • Add dbconfig.ApplyRedisPoolSize(opts *redis.Options) (new file sonic_db_config/redis_pool.go). It reads the GNMI_REDIS_POOL_SIZE environment variable and sets opts.PoolSize only when the variable is set to a positive integer.
  • If the variable is not set (or invalid), the options are left unchanged, so go-redis keeps its existing default pool size. This makes the change a no-op unless an operator opts in.
  • Apply the helper to all production redis client creations:
    • sonic_data_client/db_client.go (initRedisDbClients, useRedisTcpClient)
    • sonic_data_client/events_client.go
    • sonic_data_client/mixed_db_client.go
    • gnmi_server/connection_manager.go
    • common_utils/notification_producer.go
    • dialout/dialout_client/dialout_client.go
    • pkg/bypass/bypass.go
    • pkg/interceptors/dpuproxy/redis.go

How to verify it

  • Default behavior unchanged when GNMI_REDIS_POOL_SIZE is unset.
  • Set e.g. GNMI_REDIS_POOL_SIZE=2 for the telemetry process and confirm reduced/stable RSS on high-CPU systems:
    echo "RSS=$(grep VmRSS /proc/$(pidof telemetry)/status | awk '{print $2,$3}')"
  • Open redis sockets become ~#clients * PoolSize and no longer scale with CPU count.

Fixes sonic-net/sonic-buildimage#26825

After the go-redis v9 migration (sonic-net#528), each redis client defaults its
PoolSize to 10*GOMAXPROCS, which scales with logical CPUs. GNMI creates
one client per DB per namespace, so telemetry RSS grows with CPU count
(sonic-net/sonic-buildimage#26825).

Add dbconfig.ApplyRedisPoolSize() which sets PoolSize from the
GNMI_REDIS_POOL_SIZE env var. When the var is unset or invalid, the
default pool size is left unchanged. Applied to all production redis
client creations.

Signed-off-by: Michael Ma <kema2@microsoft.com>
Copilot AI review requested due to automatic review settings June 22, 2026 17:58
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jun 22, 2026

Copy link
Copy Markdown

CLA Not Signed

@mssonicbld

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Copilot AI 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.

Pull request overview

This PR adds an opt-in mechanism to cap go-redis connection pool sizes (via GNMI_REDIS_POOL_SIZE) to reduce telemetry RSS growth on high-CPU systems after the go-redis v9 migration, and applies it consistently across the various Redis client creation sites in the codebase.

Changes:

  • Introduce dbconfig.ApplyRedisPoolSize(*redis.Options) to optionally override redis.Options.PoolSize from GNMI_REDIS_POOL_SIZE.
  • Update Redis client initialization sites to construct redis.Options, apply the helper, then create clients.
  • Extend the change to additional packages (e.g., bypass path and DPU proxy adapter) to keep Redis client behavior consistent.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
sonic_db_config/redis_pool.go Adds env-driven helper to optionally override go-redis PoolSize.
sonic_data_client/mixed_db_client.go Applies pool-size helper for mixed DB Redis clients.
sonic_data_client/events_client.go Applies pool-size helper for COUNTERS_DB Redis client used by event stats updater.
sonic_data_client/db_client.go Applies pool-size helper for TCP/unix Redis clients created for targets/namespaces.
pkg/interceptors/dpuproxy/redis.go Applies pool-size helper to DPU proxy Redis client creation.
pkg/bypass/bypass.go Applies pool-size helper to bypass path CONFIG_DB client creation.
gnmi_server/connection_manager.go Applies pool-size helper to connection manager’s STATE_DB Redis client creation.
dialout/dialout_client/dialout_client.go Applies pool-size helper to dial-out CONFIG_DB Redis client creation (unix/tcp).
common_utils/notification_producer.go Applies pool-size helper to notification producer’s STATE_DB Redis client creation.

Comment thread sonic_db_config/redis_pool.go Outdated
Comment on lines +1 to +2
// Package dbconfig redis_pool.go provides optional, environment-driven tuning
// of the redis client connection pool used by gNMI's redis clients.
Comment on lines +35 to +40
n, err := strconv.Atoi(v)
if err != nil || n <= 0 {
log.Warningf("Ignoring invalid %s=%q (must be a positive integer): %v",
RedisPoolSizeEnvVar, v, err)
return
}
Comment on lines +18 to +26
// ApplyRedisPoolSize sets opts.PoolSize from the GNMI_REDIS_POOL_SIZE
// environment variable.
//
// If the variable is unset, empty, or not a positive integer, opts is left
// unchanged so go-redis keeps its default pool size (10 * runtime.GOMAXPROCS),
// which scales with the number of logical CPUs. Setting the variable lets
// operators cap per-client connections (and their buffers) on high-CPU
// systems to reduce memory consumption.
func ApplyRedisPoolSize(opts *redis.Options) {
Comment thread common_utils/notification_producer.go Outdated
Comment on lines 39 to 42
rclient := redis.NewClient(opts)
if rclient == nil {
return nil, fmt.Errorf("Cannot create redis client.")
}
Comment on lines +52 to 55
rclient = redis.NewClient(opts)

res, _ := rclient.HGetAll(context.Background(), "TELEMETRY_CONNECTIONS").Result()

- redis_pool.go: drop package-doc form on second file; separate parse-error
  from non-positive value in the warning; add unit tests
- notification_producer.go: remove dead redis.NewClient nil check and now-unused fmt import
- connection_manager.go: use table constant and handle HGetAll error

Signed-off-by: Michael Ma <kema2@microsoft.com>
@mssonicbld

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@hdwhdw
hdwhdw self-requested a review July 7, 2026 03:08
Comment thread pkg/bypass/bypass.go
"github.com/golang/glog"
gnmipb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/redis/go-redis/v9"
sdcfg "github.com/sonic-net/sonic-gnmi/sonic_db_config"

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.

This import breaks the pure build because sonic_db_config also pulls in swsscommon. Could we move the existing implementation and test to a pure package like:

// internal/redisopts/redis_pool.go
package redisopts

const PoolSizeEnvVar = "GNMI_REDIS_POOL_SIZE"

func ApplyPoolSize(opts *redis.Options) {
    // Existing parsing and validation logic.
}

Then add internal/redisopts to PURE_PACKAGES in pure.mk and update the call sites to:

import "github.com/sonic-net/sonic-gnmi/internal/redisopts"

redisopts.ApplyPoolSize(opts)

// RedisPoolSizeEnvVar is the environment variable used to override the redis
// client connection pool size. When it is not set, callers must leave the
// go-redis default pool size unchanged.
const RedisPoolSizeEnvVar = "GNMI_REDIS_POOL_SIZE"

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.

Is there a sonic-buildimage PR associated with this change?

@dgsudharsan

Copy link
Copy Markdown

@make1980 Can you please provide ETA to address the comments? I assume you need to create another PR in sonic-buildimage to fix the bug. Can you let us know ETA for that as well?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: [GNMI] Memory consumption increase after redis update

5 participants