Skip to content

Commit

Permalink
Redis cluster support (#20)
Browse files Browse the repository at this point in the history
* Redis cluster spport and unit tests

* Readme update

* Redis version 6 or below
  • Loading branch information
barats authored Feb 28, 2023
1 parent d5057b8 commit 828922b
Show file tree
Hide file tree
Showing 12 changed files with 331 additions and 85 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ username =
password =
pool_size = 50

# Redis 集群配置
[redis-cluster]
hosts = localhost:6371,localhost:6372,localhost:6373,localhost:6374,localhost:6375,localhost:6376
username =
password =
pool_size = 50

# Postgresql 数据库配置信息
[postgres]
host = localhost
Expand Down
6 changes: 6 additions & 0 deletions config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ username=
password=
pool_size = 50

[redis-cluster]
hosts = localhost:6371,localhost:6372,localhost:6373,localhost:6374,localhost:6375,localhost:6376
username = default
password = He110_
pool_size = 50

[postgres]
host = localhost
port = 55432
Expand Down
2 changes: 1 addition & 1 deletion docker/admin.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
##
## Build
##
FROM golang:1.16-alpine AS ohurlshortener_builder
FROM golang:1.18-alpine AS ohurlshortener_builder
ENV GO111MODULE=on
ENV GOPROXY=https://proxy.golang.com.cn,direct
ADD . /app
Expand Down
6 changes: 6 additions & 0 deletions docker/docker_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ username =
password =
pool_size = 50

[redis-cluster]
hosts =
username =
password =
pool_size =

[postgres]
host = postgres
port = 5432
Expand Down
2 changes: 1 addition & 1 deletion docker/portal.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
##
## Build
##
FROM golang:1.16-alpine AS ohurlshortener_builder
FROM golang:1.18-alpine AS ohurlshortener_builder
ENV GO111MODULE=on
ENV GOPROXY=https://proxy.golang.com.cn,direct
ADD . /app
Expand Down
13 changes: 11 additions & 2 deletions docker/vars.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

# ohUrlShortenerAdmin
OH_ADMIN_PORT=9092
OH_ADMIN_VERSION=1.8
OH_ADMIN_VERSION=1.9
OH_ADMIN_CONTAINER_NAME=ohurlshortener_admin

# ohUrlShortenerPortal
OH_PORTAL_PORT=9091
OH_PORTAL_VERSION=1.8
OH_PORTAL_VERSION=1.9
OH_PORTAL_CONTAINER_NAME=ohurlshortener_portal

# Postgresql Vars
Expand All @@ -21,3 +21,12 @@ PG_LOCAL_PORT=55432
RD_VERSION=6.2.6
RD_CONTAINER_NAME=ohurlshortener_redis
RD_LOCAL_PORT=56379

REDIS_VERSION = 6.0.17
REDIS_PASSWORD = He110_
REDIS_PORT1 = 56531
REDIS_PORT2 = 56532
REDIS_PORT3 = 56533
REDIS_PORT4 = 56534
REDIS_PORT5 = 56535
REDIS_PORT6 = 56536
40 changes: 31 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,31 +1,53 @@
module ohurlshortener

go 1.16
go 1.18

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/bxcodec/faker/v3 v3.8.0
github.com/dchest/captcha v1.0.0
github.com/gin-gonic/gin v1.8.1
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/go-redis/redis/v8 v8.11.5
github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.7
github.com/xuri/excelize/v2 v2.6.1
golang.org/x/sync v0.1.0
gopkg.in/ini.v1 v1.67.0
)

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.7
github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/xuri/excelize/v2 v2.6.1
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
golang.org/x/crypto v0.3.0 //indirect
golang.org/x/sync v0.1.0
golang.org/x/net v0.2.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v2 v2.4.0 // indirect
)
51 changes: 0 additions & 51 deletions go.sum

Large diffs are not rendered by default.

87 changes: 73 additions & 14 deletions storage/base_redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package storage

import (
"context"
"log"
"time"

"ohurlshortener/utils"
Expand All @@ -24,28 +25,52 @@ var (

// RedisService Redis 服务
type RedisService struct {
redisClient *redis.Client
redisClient *redis.Client
redisClusterClient *redis.ClusterClient
clusterMode bool
}

// InitRedisService 初始化 Redis 服务
func InitRedisService() (*RedisService, error) {
redisClient := redis.NewClient(&redis.Options{
Addr: utils.RedisConfig.Host,
DB: utils.RedisConfig.Database,
Username: utils.RedisConfig.User,
Password: utils.RedisConfig.Password,
PoolSize: utils.RedisConfig.PoolSize,

redisClusterClient := redis.NewClusterClient(&redis.ClusterOptions{

This comment has been minimized.

Copy link
@houseme

houseme Feb 28, 2023

Contributor

可以直接使用NewUniversalClient 兼容俩者

文档:https://redis.uptrace.dev/zh/guide/universal.html

This comment has been minimized.

Copy link
@barats

barats Mar 1, 2023

Author Owner

很 cool,没做过这方面的测试,我再试试看。

Addrs: utils.RedisClusterConfig.Hosts,
Username: utils.RedisClusterConfig.User,
Password: utils.RedisClusterConfig.Password,
PoolSize: utils.RedisClusterConfig.PoolSize,
})
_, err := redisClient.Ping(ctx).Result()

_, err := redisClusterClient.Ping(ctx).Result()
if err != nil {
return nil, err
log.Println(err)
log.Println("Failed to connect to Redis cluster. Will try to connect to single node.")
// If there's any error while connecting to Redis cluster,
// then try to connect to single Redis node.
redisClient := redis.NewClient(&redis.Options{
Addr: utils.RedisConfig.Host,
DB: utils.RedisConfig.Database,
Username: utils.RedisConfig.User,
Password: utils.RedisConfig.Password,
PoolSize: utils.RedisConfig.PoolSize,
})
_, err := redisClient.Ping(ctx).Result()
if err != nil {
return nil, err
}
redisService.redisClient = redisClient
} else {
redisService.clusterMode = true
redisService.redisClusterClient = redisClusterClient
}
redisService.redisClient = redisClient

return redisService, nil
}

// RedisSet 设置 Redis 键值对
func RedisSet(key string, value interface{}, ttl time.Duration) error {
if redisService.clusterMode {
return redisService.redisClusterClient.Set(ctx, key, value, ttl).Err()
}
return redisService.redisClient.Set(ctx, key, value, ttl).Err()
}

Expand All @@ -62,16 +87,36 @@ func RedisSet4Ever(key string, value interface{}) error {
// RedisScan4Keys 获取 Redis 中所有以 prefix 开头的键
func RedisScan4Keys(prefix string) ([]string, error) {
var keys []string
sc := redisService.redisClient.Scan(ctx, 0, prefix, 0).Iterator()
var sc *redis.ScanIterator
if redisService.clusterMode {
err := redisService.redisClusterClient.ForEachMaster(ctx, func(ctx context.Context, client *redis.Client) error {
sc = client.Scan(ctx, 0, prefix, 0).Iterator()
for sc.Next(ctx) {
keys = append(keys, sc.Val())
}
return sc.Err()
})
if err != nil {
return keys, err
}
} else {
sc = redisService.redisClient.Scan(ctx, 0, prefix, 0).Iterator()
}
for sc.Next(ctx) {
keys = append(keys, sc.Val())
}
return keys, nil
return keys, sc.Err()
}

// RedisGetString 获取 Redis 中的字符串
func RedisGetString(key string) (string, error) {
result, err := redisService.redisClient.Get(ctx, key).Result()
var result string
var err error
if redisService.clusterMode {
result, err = redisService.redisClusterClient.Get(ctx, key).Result()
} else {
result, err = redisService.redisClient.Get(ctx, key).Result()
}
if err == redis.Nil {
return result, nil
}
Expand All @@ -80,13 +125,27 @@ func RedisGetString(key string) (string, error) {

// RedisFlushDB 清空 Redis 中的所有键值对
func RedisFlushDB() error {
if redisService.clusterMode {
return redisService.redisClusterClient.ForEachMaster(ctx, func(ctx context.Context, client *redis.Client) error {
return client.FlushDB(ctx).Err()
})
}
return redisService.redisClient.FlushDB(ctx).Err()
}

// RedisDelete 删除 Redis 中的键值对
func RedisDelete(key ...string) error {
if len(key) > 0 {
return redisService.redisClient.Del(ctx, key...).Err()
if redisService.clusterMode {
// Apprently you can NOT delete multiple keys in one request,since keys are distributed across multiple nodes.
var err error
for _, k := range key {
err = redisService.redisClusterClient.Del(ctx, k).Err()
}
return err
} else {
return redisService.redisClient.Del(ctx, key...).Err()
}
}
return nil
}
Loading

0 comments on commit 828922b

Please sign in to comment.