diff --git a/docs/en/redis_best_practices.md b/docs/en/redis_best_practices.md index 6371110f0c64..896b278d003b 100644 --- a/docs/en/redis_best_practices.md +++ b/docs/en/redis_best_practices.md @@ -29,6 +29,15 @@ There're some [fundamental things](https://redis.io/topics/sentinel#fundamental- Please read the [official documentation](https://redis.io/topics/sentinel) for more information. +Once Redis servers and Sentinels are deployed, the `REDIS-URL` can be specified as `[redis[s]://][USER:PASSWORD@]MASTERNAME,SENTINEL_ADDRS:SENTINEL_PORT[/DB]`, for example, + +``` +$ ./juicefs mount rediss://:sentinelPass@masterName,1.2.3.4,1.2.5.6:5000/2 +``` +**Note** The default port for Sentinel is 26379, but the above URL use 6379 (default port for Redis server) as the default, so the port for Sentinel is not optional. + +**Note** When the password is provided in the URL, it will also be used to connect Redis server. If they have different passwords, the passwords should be specified by enviroment viarables (`SENTINEL_PASSWORD` and `REDIS_PASSWORD`) separately. + ## Data Durability Redis provides a different range of [persistence](https://redis.io/topics/persistence) options: diff --git a/pkg/meta/redis.go b/pkg/meta/redis.go index b8231ff29e03..cbfe3f244f95 100644 --- a/pkg/meta/redis.go +++ b/pkg/meta/redis.go @@ -23,6 +23,7 @@ import ( "fmt" "hash/fnv" "math/rand" + "net" "os" "strconv" "strings" @@ -114,13 +115,46 @@ func NewRedisMeta(url string, conf *RedisConfig) (Meta, error) { if err != nil { return nil, fmt.Errorf("parse %s: %s", url, err) } - if opt.Password == "" && os.Getenv("REDIS_PASSWORD") != "" { - opt.Password = os.Getenv("REDIS_PASSWORD") + var rdb *redis.Client + if strings.Contains(opt.Addr, ",") { + var fopt redis.FailoverOptions + ps := strings.Split(opt.Addr, ",") + fopt.MasterName = ps[0] + fopt.SentinelAddrs = ps[1:] + _, port, _ := net.SplitHostPort(fopt.SentinelAddrs[len(fopt.SentinelAddrs)-1]) + if port != "" { + for i := range fopt.SentinelAddrs { + h, p, _ := net.SplitHostPort(fopt.SentinelAddrs[i]) + if p == "" { + fopt.SentinelAddrs[i] = net.JoinHostPort(h, port) + } + } + } + // Assume Redis server and sentinel have the same password. + fopt.SentinelPassword = opt.Password + fopt.Username = opt.Username + fopt.Password = opt.Password + if fopt.SentinelPassword == "" && os.Getenv("SENTINEL_PASSWORD") != "" { + fopt.SentinelPassword = os.Getenv("SENTINEL_PASSWORD") + } + if fopt.Password == "" && os.Getenv("REDIS_PASSWORD") != "" { + fopt.Password = os.Getenv("REDIS_PASSWORD") + } + fopt.DB = opt.DB + fopt.TLSConfig = opt.TLSConfig + fopt.MaxRetries = conf.Retries + fopt.MinRetryBackoff = time.Millisecond * 100 + fopt.MaxRetryBackoff = time.Minute * 1 + rdb = redis.NewFailoverClient(&fopt) + } else { + if opt.Password == "" && os.Getenv("REDIS_PASSWORD") != "" { + opt.Password = os.Getenv("REDIS_PASSWORD") + } + opt.MaxRetries = conf.Retries + opt.MinRetryBackoff = time.Millisecond * 100 + opt.MaxRetryBackoff = time.Minute * 1 + rdb = redis.NewClient(opt) } - opt.MaxRetries = conf.Retries - opt.MinRetryBackoff = time.Millisecond * 100 - opt.MaxRetryBackoff = time.Minute * 1 - rdb := redis.NewClient(opt) m := &redisMeta{ conf: conf, rdb: rdb,