Categorygithub.com/goclub/redis
modulepackage
0.0.0-20240416020153-0fa6226974d9
Repository: https://github.com/goclub/redis.git
Documentation: pkg.go.dev

# README


permalink: / sidebarBasedOnContent: true

goclub/redis

Go Reference

易用性

go 社区有很多 redis 库, 但是大多数库在 redis 返回 nil 时候用 error 表示.例如使用GET方法:

cmd := client.Get(ctx, "name")
err = cmd.Err()
isNil := false
if err != nil {
    if errors.Is(err, redis.Nil) {
        isNil = true
    } else {
        return err
    }
}
if isNil {
    // do some
} else {
    log.Print(cmd.String())
}

代码写的复杂,心很累.

goclub/redis 的接口风格是

value, isNil, err := red.GET{Key:key}.Do(ctx, client) ; if err != nil {
    return
}
if isNil {
	// do some
} else {
	log.Print(value)
}

自由

redis 的核心是 RESP 协议. goclub/redis 提供以下接口对应 RESP.

// Connecter RESP
type Connecter interface {
	DoStringReply(ctx context.Context, args []string) (reply string, isNil bool, err error)
	DoStringReplyWithoutNil(ctx context.Context, args []string) (reply string, err error)
	DoIntegerReply(ctx context.Context, args []string) (reply int64, isNil bool, err error)
	DoIntegerReplyWithoutNil(ctx context.Context, args []string) (reply int64, err error)
	DoArrayIntegerReply(ctx context.Context, args []string) (reply []OptionInt64, err error)
	DoArrayStringReply(ctx context.Context, args []string) (reply []OptionString, err error)
	Eval(ctx context.Context, script Script) (reply Reply, isNil bool, err error)
	EvalWithoutNil(ctx context.Context, script Script) (reply Reply, err error)
}

你可以自由的使用任何命令.

replyInt64, err = client.DoIntegerReplyWithoutNil(
	ctx, 
	[]string{
		"HSET", key, "name", "goclub", "age", "18",
	})
if err != nil {
    return
}

你也可以查看 red.API 查看 goclub/redis 对哪些方法进行了封装


像是 RESP Simple Strings 这类操作你可以根据 redis 是否会返回 nil 去调用 DoStringReplyDoStringReplyWithoutNil

脚本则使用 Eval 或者EvalWithoutNil

script := `
if redis.call("GET", KEYS[1]) == ARGV[1]
then
	return redis.call("DEL", KEYS[1])
else
	return 0
end
`
reply, err := client.EvalWithoutNil(ctx, Script{
    KEYS: []string{key},
    ARGV: []string{value},
    Script: script,
}) ; if err != nil {
    return
}
/*
你可以根据 script 内容调用一下 reply 方法
reply.Int64()
reply.Uint64()
reply.String()
reply.Int64Slice()
reply.StringSlice()
*/

包容

你可以将 goclub/redis 理解为是一个驱动库,是一个"壳". goclub/redis 能通过接口适配 go 社区的说有 redis 库.

goredis 是非常流行的库, goclub/redis 默认支持了 goredisv8

直接来吧

连接redis | NewClient

字符串增删改查 | StringsCRUD

eval执行脚本 | Eval

直接写命令 |l DoIntegerReply

实用方法

goclub/redis 还基于redis实现了了一些实用的方法,帮助开发人员提高开发效率.防止重复造轮子.

Trigger

触发器

// Trigger 触发器
// 每5分钟出现3次则触发,但是10分钟内只触发一次
func exmaple () {
	triggered, err := red.Trigger{
		Namespace: "pay_fail_alarm",
		Interval: time.Minute*5,
		Threshold: 3,
		Frequency: time.Minute*5,
	}.Do(ctx, client) ; if err != nil {
	    return
	}
	if triggered {
		// do some
	}
}

Mutex

互斥锁

mutex := red.Mutex{
    Key: key,
	// Expire 控制锁定时间
    Expire: time.Millisecond*100,
	// Retry 当锁被占用时进入循环重试(此时会堵塞)
	// Retry.Times 重试上锁多少次
	// Retry.Interval 重试上锁间隔
    Retry: red.Retry{
        Times: 3,
		Interval:time.Millisecond*100,
    },
}
lockSuccess, unlock, err := mutex.Lock(context.TODO(), client) ; if err != nil {
    // 锁失败
    return
}
if lockSuccess == false {
    // 锁被占用
    return
}
// 处理某些业务
err = unlock(context.TODO()) ; if err != nil {
    *mutexCount--
	// 解锁失败
	log.Printf("%+v", err)
    return
}
// 解锁成功

IncrLimiter

递增限制器

alarm_1 := IncrLimiter{
    Namespace: "incr_limiter_alarm_1",
    Expire:    time.Second * 10,
    Maximum:   3,
}
/* 第1次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第2次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第3次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第4次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
    return
} // limited = true

SetLimiter

设值限制器

使用场景: 限制用户每天只能试读3个章节(如果不允许一天内反复试读相同章节则可以使用 IncrLimiter )
注意:
如果 Key = free_trial:{userID} Expire = 24h 是限制24小时
如果 Key = free_trial:2022-01-01:{userID} Expire = 24h 是限制每天

/* 第1次 用户1访问了章节1 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "1"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第2次 用户1重复访问了章节1 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "1"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第3次 用户1访问了章节2 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "2"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第4次 用户1访问了章节3 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "3"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = false

/* 第5次 用户1访问了章节4 */
limited, err := SetLimiter{
    Key:       "free_trial:2022-05-25:userID:1",
    Member:    "4"
    Expire:    time.Hour * 24,
    Maximum:   3,
}.Do(ctx, client) ; if err != nil {
    return
} // limited = true

# Packages

No description provided by the author

# Functions

No description provided by the author
No description provided by the author
MakeKey MakeKey("user", today, "count") // "user:2022-01-01:count".
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Variables

No description provided by the author

# Structs

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
bit operation.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
IncrLimiter 递增限制器 eg:消息队列:重新入队:消息ID作为key在1分钟内只能递增3次.三次内返回的Limited为false,超过三次为true.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
SetLimiter 集合限制器 使用场景: 限制用户每天只能试读3个章节(如果不允许一天内反复试读相同章节则可以使用 IncrLimiter ).
No description provided by the author
No description provided by the author
Trigger 触发器 每5分钟出现3次则触发,但是10分钟内只触发一次 func exmaple () { triggered, err := Trigger{ Namespace: "pay_fail_alarm", Interval: time.Minute*5, Threshold: 3, Frequency: time.Minute*5, }.Do(ctx, client) ; if err != nil { return } if triggered { // do some } }.
No description provided by the author

# Interfaces

Connecter RESP.