Skip to content

Commit

Permalink
meta/redis:support unix socket for redis (#2319)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhijian-pro authored Jun 29, 2022
1 parent 252ba50 commit 8311f97
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 20 deletions.
12 changes: 12 additions & 0 deletions docs/en/reference/how_to_setup_metadata_engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ JuiceFS requires Redis 4.0+
When using Redis as the metadata storage engine, the following format is usually used to access the database:

```shell
# use tcp
redis[s]://[<username>:<password>@]<host>[:<port>]/<db>

# use unix socket
unix://[<username>:<password>@]<socket-file-path>?db=<db>
```

Where `[]` enclosed are optional and the rest are mandatory.
Expand Down Expand Up @@ -119,7 +123,11 @@ Other PostgreSQL-compatible databases (such as CockroachDB) can also be used as
When using PostgreSQL as the metadata storage engine, you need to create a database manually before creating the file system by following the format below:

```shell
# use tcp
postgres://<username>[:<password>]@<host>[:5432]/<database-name>[?parameters]

# use unix socket
postgres:///<database-name>?host=<socket-directories-path>
```

Where `[]` enclosed are optional and the rest are mandatory.
Expand Down Expand Up @@ -178,7 +186,11 @@ Additional parameters can be appended to the metadata URL. More details can be s
When using MySQL as the metadata storage engine, you need to create a database manually before create the file system. The command with the following format is usually used to access the database:

```shell
# use tcp
mysql://<username>[:<password>]@(<host>:3306)/<database-name>

# use unix socket
mysql://<username>[:<password>]@unix(<socket-file-path>)/<database-name>
```

:::note
Expand Down
12 changes: 12 additions & 0 deletions docs/zh_cn/reference/how_to_setup_metadata_engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ JuiceFS 要求 Redis 4.0+ 版本
使用 Redis 作为元数据存储引擎时,通常使用以下格式访问数据库:

```shell
# 使用 tcp 方式
redis[s]://[<username>:<password>@]<host>[:<port>]/<db>

# 使用 unix socket 方式
unix://[<username>:<password>@]<socket-file-path>?db=<db>
```

其中,`[]` 括起来的是可选项,其它部分为必选项。
Expand Down Expand Up @@ -117,7 +121,11 @@ KeyDB 的数据复制是异步的,使用 `Active Active` "双活"功能可能
使用 PostgreSQL 作为元数据引擎时,需要提前手动创建数据库,使用如下的格式来指定参数:

```shell
# tcp 方式
postgres://<username>[:<password>]@<host>[:5432]/<database-name>[?parameters]

# 使用 unix socket 方式
postgres:///<database-name>?host=<socket-directories-path>
```

其中,`[]` 括起来的是可选项,其它部分为必选项。
Expand Down Expand Up @@ -176,7 +184,11 @@ $ juicefs format --storage s3 \
使用 MySQL 作为元数据存储引擎时,需要提前手动创建数据库,通常使用以下格式访问数据库:

```shell
# 使用 tcp 方式
mysql://<username>[:<password>]@(<host>:3306)/<database-name>

# 使用 unix socket 方式
mysql://<username>[:<password>]@unix(<socket-file-path>)/<database-name>
```

:::note 注意
Expand Down
34 changes: 17 additions & 17 deletions pkg/meta/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,27 +84,27 @@ var _ Meta = &redisMeta{}
func init() {
Register("redis", newRedisMeta)
Register("rediss", newRedisMeta)
Register("unix", newRedisMeta)
}

// newRedisMeta return a meta store using Redis.
func newRedisMeta(driver, addr string, conf *Config) (Meta, error) {
uri := driver + "://" + addr
var query queryMap
if p := strings.Index(uri, "?"); p > 0 && p+1 < len(uri) {
if q, err := url.ParseQuery(uri[p+1:]); err == nil {
logger.Debugf("parsed query parameters: %v", q)
query = queryMap{q}
uri = uri[:p]
} else {
return nil, fmt.Errorf("parse query %s: %s", uri[p+1:], err)
}
}
u, err := url.Parse(uri)
if err != nil {
return nil, fmt.Errorf("url parse %s: %s", uri, err)
}
values := u.Query()
query := queryMap{&values}
minRetryBackoff := query.duration("min-retry-backoff", "min_retry_backoff", time.Millisecond*20)
maxRetryBackoff := query.duration("max-retry-backoff", "max_retry_backoff", time.Second*10)
readTimeout := query.duration("read-timeout", "read_timeout", time.Second*30)
writeTimeout := query.duration("write-timeout", "write_timeout", time.Second*5)
routeRead := query.pop("route-read")
u.RawQuery = values.Encode()

hosts := u.Host
opt, err := redis.ParseURL(uri)
opt, err := redis.ParseURL(u.String())
if err != nil {
return nil, fmt.Errorf("redis parse %s: %s", uri, err)
}
Expand All @@ -118,10 +118,10 @@ func newRedisMeta(driver, addr string, conf *Config) (Meta, error) {
if opt.MaxRetries == 0 {
opt.MaxRetries = -1 // Redis use -1 to disable retries
}
opt.MinRetryBackoff = query.duration("min-retry-backoff", time.Millisecond*20)
opt.MaxRetryBackoff = query.duration("max-retry-backoff", time.Second*10)
opt.ReadTimeout = query.duration("read-timeout", time.Second*30)
opt.WriteTimeout = query.duration("write-timeout", time.Second*5)
opt.MinRetryBackoff = minRetryBackoff
opt.MaxRetryBackoff = maxRetryBackoff
opt.ReadTimeout = readTimeout
opt.WriteTimeout = writeTimeout
var rdb redis.UniversalClient
var prefix string
if strings.Contains(hosts, ",") && strings.Index(hosts, ",") < strings.Index(hosts, ":") {
Expand Down Expand Up @@ -153,7 +153,7 @@ func newRedisMeta(driver, addr string, conf *Config) (Meta, error) {
fopt.WriteTimeout = opt.WriteTimeout
if conf.ReadOnly {
// NOTE: RouteByLatency and RouteRandomly are not supported since they require cluster client
fopt.SlaveOnly = query.Get("route-read") == "replica"
fopt.SlaveOnly = routeRead == "replica"
}
rdb = redis.NewFailoverClient(&fopt)
} else {
Expand All @@ -179,7 +179,7 @@ func newRedisMeta(driver, addr string, conf *Config) (Meta, error) {
copt.ReadTimeout = opt.ReadTimeout
copt.WriteTimeout = opt.WriteTimeout
if conf.ReadOnly {
switch query.Get("route-read") {
switch routeRead {
case "random":
copt.RouteRandomly = true
case "latency":
Expand Down
17 changes: 14 additions & 3 deletions pkg/meta/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,20 @@ type freeID struct {
var logger = utils.GetLogger("juicefs")

type queryMap struct {
url.Values
*url.Values
}

func (qm *queryMap) duration(key string, d time.Duration) time.Duration {
func (qm *queryMap) duration(key, originalKey string, d time.Duration) time.Duration {
val := qm.Get(key)
if val == "" {
return d
oVal := qm.Get(originalKey)
if oVal == "" {
return d
}
val = oVal
}

qm.Del(key)
if dur, err := time.ParseDuration(val); err == nil {
return dur
} else {
Expand All @@ -77,6 +83,11 @@ func (qm *queryMap) duration(key string, d time.Duration) time.Duration {
}
}

func (qm *queryMap) pop(key string) string {
defer qm.Del(key)
return qm.Get(key)
}

func errno(err error) syscall.Errno {
if err == nil {
return 0
Expand Down

0 comments on commit 8311f97

Please sign in to comment.