Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Redis Sentinel #4235

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions configuration/configuration.go
Expand Up @@ -271,11 +271,23 @@ type FileChecker struct {
Threshold int `yaml:"threshold,omitempty"`
}

type RedisSentinel struct {
// MasterName specifies the name of the master sentinel.
MasterName string `yaml:"masterName,omitempty"`

// Addresses specifies the addresses of the sentinels.
Addresses []string `yaml:"addresses,omitempty"`
}

// Redis configures the redis pool available to the registry webapp.
type Redis struct {
// Addr specifies the the redis instance available to the application.
Addr string `yaml:"addr,omitempty"`

// Sentinel specifies the sentinel instance available to the application.
// If this is set, the Addr field is ignored.
Sentinel RedisSentinel `yaml:"sentinel,omitempty"`

// Usernames can be used as a finer-grained permission control since the introduction of the redis 6.0.
Username string `yaml:"username,omitempty"`

Expand Down
62 changes: 41 additions & 21 deletions registry/handlers/app.go
Expand Up @@ -487,12 +487,12 @@ func (app *App) configureEvents(configuration *configuration.Configuration) {
}

func (app *App) configureRedis(cfg *configuration.Configuration) {
if cfg.Redis.Addr == "" {
if cfg.Redis.Addr == "" && (len(cfg.Redis.Sentinel.Addresses) == 0 || cfg.Redis.Sentinel.MasterName == "") {
dcontext.GetLogger(app).Infof("redis not configured")
return
}

app.redis = app.createPool(cfg.Redis)
app.redis = app.createRedisClient(cfg.Redis)

// Enable metrics instrumentation.
if err := redisotel.InstrumentMetrics(app.redis); err != nil {
Expand All @@ -514,25 +514,45 @@ func (app *App) configureRedis(cfg *configuration.Configuration) {
}))
}

func (app *App) createPool(cfg configuration.Redis) *redis.Client {
return redis.NewClient(&redis.Options{
Addr: cfg.Addr,
OnConnect: func(ctx context.Context, cn *redis.Conn) error {
res := cn.Ping(ctx)
return res.Err()
},
Username: cfg.Username,
Password: cfg.Password,
DB: cfg.DB,
MaxRetries: 3,
DialTimeout: cfg.DialTimeout,
ReadTimeout: cfg.ReadTimeout,
WriteTimeout: cfg.WriteTimeout,
PoolFIFO: false,
MaxIdleConns: cfg.Pool.MaxIdle,
PoolSize: cfg.Pool.MaxActive,
ConnMaxIdleTime: cfg.Pool.IdleTimeout,
})
func (app *App) createRedisClient(cfg configuration.Redis) *redis.Client {
// This function assumes that cfg.Addresses is not empty, which is checked by the caller.
if len(cfg.Sentinel.Addresses) > 0 && cfg.Sentinel.MasterName != "" {
return redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: cfg.Sentinel.MasterName,
SentinelAddrs: cfg.Sentinel.Addresses,
OnConnect: nil,
Username: cfg.Username,
Password: cfg.Password,
DB: cfg.DB,
MaxRetries: 3,
DialTimeout: cfg.DialTimeout,
ReadTimeout: cfg.ReadTimeout,
WriteTimeout: cfg.WriteTimeout,
PoolFIFO: false,
MaxIdleConns: cfg.Pool.MaxIdle,
PoolSize: cfg.Pool.MaxActive,
ConnMaxIdleTime: cfg.Pool.IdleTimeout,
})
} else {
return redis.NewClient(&redis.Options{
Addr: cfg.Addr,
OnConnect: func(ctx context.Context, cn *redis.Conn) error {
res := cn.Ping(ctx)
return res.Err()
},
Username: cfg.Username,
Password: cfg.Password,
DB: cfg.DB,
MaxRetries: 3,
DialTimeout: cfg.DialTimeout,
ReadTimeout: cfg.ReadTimeout,
WriteTimeout: cfg.WriteTimeout,
PoolFIFO: false,
MaxIdleConns: cfg.Pool.MaxIdle,
PoolSize: cfg.Pool.MaxActive,
ConnMaxIdleTime: cfg.Pool.IdleTimeout,
})
}
}

// configureLogHook prepares logging hook parameters.
Expand Down