支持单机、哨兵、集群
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
module code.yun.ink/pkg/redisx
|
module code.yun.ink/pkg/redisx
|
||||||
|
|
||||||
go 1.20
|
go 1.24
|
||||||
|
|
||||||
require github.com/go-redis/redis/v8 v8.11.5
|
require github.com/redis/go-redis/v9 v9.19.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
||||||
|
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||||
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
|||||||
+50
-7
@@ -1,24 +1,67 @@
|
|||||||
package redisx
|
package redisx
|
||||||
|
|
||||||
type redisOption struct {
|
type redisOption struct {
|
||||||
addr string
|
mode RedisMode // 模式:single / cluster / sentinel,默认 single
|
||||||
password string
|
address []string // 单机/集群地址:["127.0.0.1:6379"]
|
||||||
db int
|
password string // 密码
|
||||||
poolSize int
|
db int // 单机/哨兵
|
||||||
|
poolSize int
|
||||||
|
enableTLS bool `yaml:"enable_tls"` // 是否启用TLS,默认false
|
||||||
|
sentinels []string `yaml:"sentinels"` // 哨兵模式地址,例如: ["127.0.0.1:26379"]
|
||||||
|
masterName string `yaml:"master_name"` // 哨兵监控的主节点名称
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RedisMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RedisModeSingle RedisMode = "single" // 单机模式
|
||||||
|
RedisModeCluster RedisMode = "cluster" // 集群模式
|
||||||
|
RedisModeSentinel RedisMode = "sentinel" // 哨兵模式
|
||||||
|
)
|
||||||
|
|
||||||
func defaultOptions() redisOption {
|
func defaultOptions() redisOption {
|
||||||
return redisOption{
|
return redisOption{
|
||||||
addr: "localhost:6379",
|
mode: "single",
|
||||||
|
address: []string{"localhost:6379"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option func(*redisOption)
|
type Option func(*redisOption)
|
||||||
|
|
||||||
// 127.0.0.1:6379
|
// 127.0.0.1:6379
|
||||||
func SetAddress(addr string) Option {
|
func SetAddress(addrs []string) Option {
|
||||||
return func(o *redisOption) {
|
return func(o *redisOption) {
|
||||||
o.addr = addr
|
o.address = addrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetMode(mode RedisMode) Option {
|
||||||
|
return func(o *redisOption) {
|
||||||
|
o.mode = mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetPoolSize(size int) Option {
|
||||||
|
return func(o *redisOption) {
|
||||||
|
o.poolSize = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetEnableTLS(enableTLS bool) Option {
|
||||||
|
return func(o *redisOption) {
|
||||||
|
o.enableTLS = enableTLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetSentinels(sentinels []string) Option {
|
||||||
|
return func(o *redisOption) {
|
||||||
|
o.sentinels = sentinels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetMasterName(masterName string) Option {
|
||||||
|
return func(o *redisOption) {
|
||||||
|
o.masterName = masterName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ package redisx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
redis "github.com/redis/go-redis/v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PoolSize:连接池中的最大连接数。
|
// PoolSize:连接池中的最大连接数。
|
||||||
@@ -14,43 +15,66 @@ import (
|
|||||||
// IdleCheckFrequency:检查空闲连接的频率。
|
// IdleCheckFrequency:检查空闲连接的频率。
|
||||||
|
|
||||||
// 单机
|
// 单机
|
||||||
func NewRedis(opts ...Option) redis.UniversalClient {
|
func NewRedis(ctx context.Context, opts ...Option) redis.UniversalClient {
|
||||||
opt := defaultOptions()
|
opt := defaultOptions()
|
||||||
for _, apply := range opts {
|
for _, apply := range opts {
|
||||||
apply(&opt)
|
apply(&opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := redis.NewClient(&redis.Options{
|
var tlsConfig *tls.Config
|
||||||
Addr: opt.addr,
|
if opt.enableTLS {
|
||||||
Password: opt.password, // no password set
|
tlsConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
DB: opt.db, // use default DB
|
}
|
||||||
|
|
||||||
// 连接池配置参数
|
var client redis.UniversalClient
|
||||||
// PoolSize: 100, // 连接池最大连接数
|
|
||||||
// MinIdleConns: 10, // 最小空闲连接数
|
switch opt.mode {
|
||||||
// MaxConnAge: 30 * time.Minute, // 连接最大寿命
|
case RedisModeCluster:
|
||||||
// PoolTimeout: 4 * time.Second, // 等待连接池连接的最长时间
|
// 集群模式
|
||||||
// IdleTimeout: 5 * time.Minute, // 空闲连接的生命周期
|
if len(opt.address) == 0 {
|
||||||
// IdleCheckFrequency: 60 * time.Second, // 空闲连接检查频率
|
panic("redis cluster mode requires at least one address")
|
||||||
})
|
}
|
||||||
_, err := client.Ping(context.Background()).Result()
|
client = redis.NewClusterClient(
|
||||||
|
&redis.ClusterOptions{
|
||||||
|
Addrs: opt.address,
|
||||||
|
Password: opt.password, // no password set
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
case RedisModeSentinel:
|
||||||
|
// 哨兵模式
|
||||||
|
if len(opt.sentinels) == 0 {
|
||||||
|
panic("redis sentinel mode requires at least one sentinel address")
|
||||||
|
}
|
||||||
|
client = redis.NewFailoverClient(
|
||||||
|
&redis.FailoverOptions{
|
||||||
|
MasterName: opt.masterName,
|
||||||
|
SentinelAddrs: opt.sentinels,
|
||||||
|
Password: opt.password, // no password set
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
|
DB: opt.db, // use default DB
|
||||||
|
// SentinelPassword: global.Config.Redis.Password, // 哨兵认证密码(如果有)
|
||||||
|
// SentinelUsername: global.Config.Redis.Username, // 哨兵认证用户名(如果有)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
// 单机模式
|
||||||
|
if len(opt.address) == 0 {
|
||||||
|
panic("redis single mode requires an address")
|
||||||
|
}
|
||||||
|
client = redis.NewClient(
|
||||||
|
&redis.Options{
|
||||||
|
Addr: opt.address[0],
|
||||||
|
Password: opt.password, // no password set
|
||||||
|
DB: opt.db, // use default DB
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := client.Ping(ctx).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
// 集群
|
|
||||||
|
|
||||||
// 哨兵
|
|
||||||
// client = redis.NewFailoverClient(&redis.FailoverOptions{
|
|
||||||
// MasterName: "mymaster",
|
|
||||||
// SentinelAddrs: []string{"127.0.0.1:26379", "127.0.0.1:26380"},
|
|
||||||
// Password: "",
|
|
||||||
// DB: 0,
|
|
||||||
// })
|
|
||||||
// for {
|
|
||||||
// reply, err := client.Incr("pvcont").Result()
|
|
||||||
// fmt.Printf("reply=%v err=%v\n", reply, err)
|
|
||||||
// time.Sleep(1 * time.Second)
|
|
||||||
// }
|
|
||||||
|
|||||||
Reference in New Issue
Block a user