1 创建客户端
func NewClient(redis_conf string) *redis.ClusterClient {
client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: ["10.1.11.17:6379", "10.1.11.18:6379"], // master node ip list
})
return client
}
2. 基本命令
func Get(rdb *redis.ClusterClient, ctx context.Context, key string) *redis.StringCmd {
return rdb.Get(ctx, key)
}
3. lua 脚本
func LuaScriptRun(s string, ctx context.Context, rdb *redis.ClusterClient, keys []string, args ...interface{}) *redis.Cmd {
luaScript := redis.NewScript(s)
return luaScript.Run(ctx, rdb, keys, args...)
}
// move member between zset source to zset destination, both key must be in same slot
// redis slot 5542 ['zset_test_12680', 'zset_test_18865', 'zset_test_21643', 'zset_test_24131', 'zset_test_30602', 'zset_test_35170']
func Move(source string, destination string, member string, useHigherScore bool) int64 {
s := `
local source = KEYS[1]
local key = KEYS[2]
local member = ARGV[1]
if redis.call('zrank', source, member) then
local score = redis.call('zscore', source, member)
redis.call('zrem', source, member)
if ARGV[2] == "useHigherScore" then
if redis.call('exists', key) == 0 or not redis.call('zrank', key, member) then
redis.call('zadd', key, score, member)
return 1
else
local old_score = redis.call('zscore', key, member)
if score > old_score then
redis.call('zadd', key, score, member)
return 1
end
end
else
redis.call('zadd', key, score, member)
return 1
end
end
return 0
`
useHigherScoreStr := ""
if useHigherScore {
useHigherScoreStr = "useHigherScore"
}
n, err := redis_manager.LuaScriptRun(s, redis_manager.DefaultCtx, redis_manager.DefaultRdb, []string{source, destination}, member, useHigherScoreStr).Result()
if err != nil {
beego.Error(err)
return 0
}
v, ok := n.(int64)
if ok {
return v
} else {
beego.Error("return value assertion fail")
return 0
}
}
4. 分布式锁实现
type LockInfo struct {
Name string
TTL int64 // millisecond
}
var Separator = ";"
var GlobalLockMap = map[string]LockInfo{
"global_lock_demo": {"global_lock_demo", 1000},
}
type GlobalLock struct {
Name string
TTL int64
Value string
rdbCtx context.Context
rdb *redis.ClusterClient
}
func New(lockInfo conf.LockInfo, message string) *GlobalLock {
gl := new(GlobalLock)
gl.Name = lockInfo.Name
gl.TTL = lockInfo.TTL
gl.Value = util.GetRandomStr(20) + conf.Separator + message
gl.rdbCtx = redis_manager.DefaultCtx
gl.rdb = redis_manager.DefaultRdb
return gl
}
func (gl *GlobalLock) Lock() bool {
ret, err := redis_manager.SetNX(gl.rdb, gl.rdbCtx, gl.Name, gl.Value, time.Millisecond*time.Duration(gl.TTL)).Result()
if err != nil {
beego.Error(err)
}
return ret
}
func (gl *GlobalLock) Unlock() bool {
s := `
if redis.call("get", KEYS[1]) == ARGV[1] then
redis.call("del", KEYS[1])
return 1
else
return 0
end
`
n, err := redis_manager.LuaScriptRun(s, gl.rdbCtx, gl.rdb, []string{gl.Name}, gl.Value).Result()
if err != nil {
beego.Error(err)
return false
}
v, ok := n.(int64)
if ok {
if v == 1 {
return true
} else {
return false
}
} else {
beego.Error("return value assertion fail")
return false
}
}
func (gl *GlobalLock) IsLockedByMyself(refresh bool) bool {
s := `
local key = KEYS[1]
local value = ARGV[1]
local refresh = ARGV[2]
local ttl = ARGV[3]
if redis.call("get", key) == value then
if refresh == "refresh" then
redis.call("pexpire", key, ttl)
end
return 1
else
return 0
end
`
isRefresh := ""
if refresh {
isRefresh = "refresh"
}
n, err := redis_manager.LuaScriptRun(s, gl.rdbCtx, gl.rdb, []string{gl.Name}, gl.Value, isRefresh, gl.TTL).Result()
if err != nil {
beego.Error(err)
return false
}
v, ok := n.(int64)
if ok {
if v == 1 {
return true
} else {
return false
}
} else {
beego.Error("return value assertion fail")
return false
}
}
参考