go 集成go-redis 缓存操作

一、什么是Go Redis

这是一个流行的Go语言Redis客户端库,它提供了细化的API,对每个Redis命令的功能进行了封装,使得用户只需记住命令,具体的用法可以直接查看接口的声明,使用成本较低。go-redis对数据类型按照Redis底层的类型进行统一,编译时可以帮助检查参数类型,并且它的响应统一采用Result的接口返回,确保了返回参数类型的正确性,对用户更加友好。此外,go-redis还支持连接池、Pipeline和事务,以及发布订阅Pub/Sub和键空间通知等功能。

二、go-redis特性

  • 多种客户端

支持单机Redis Server、Redis Cluster、Redis Sentinel、Redis分片服务器

  • 数据类型

go-redis会根据不同的redis命令处理成指定的数据类型,不必进行繁琐的数据类型转换

  • 功能完善

go-redis支持管道(pipeline)、事务、pub/sub、Lua脚本、mock、分布式锁等功能

三、安装go-redis

go-redis/v9 (支持所有的 redis 版本)

Go 复制代码
go get github.com/redis/go-redis/v9

四、连接配置

go-redis支持多种连接方式,这里只展示一种

Go 复制代码
func InitRedis() *redis.Client {
	rdb := redis.NewClient(&redis.Options{
		Addr:     viper.GetString("db.redis.addr"),
		Password: viper.GetString("db.redis.pwd"), // 没有密码,默认值
		DB:       viper.GetInt("db.redis.db"),     // 默认DB 0
	})
	return rdb
}

五、入门

Context 上下文

go-redis 支持 Context,你可以使用它控制 超时 或者传递一些数据, 也可以 监控 go-redis 性能。

Go 复制代码
ctx := context.Background()

执行 Redis 命令

Go 复制代码
val, err := rdb.Get(ctx, "key").Result()
fmt.Println(val)

// 你也可以分别访问值和错误:

get := rdb.Get(ctx, "key")
fmt.Println(get.Val(), get.Err())

执行尚不支持的命令

可以使用 Do() 方法执行尚不支持或者任意命令:

Go 复制代码
val, err := rdb.Do(ctx, "get", "key").Result()
if err != nil {
	if err == redis.Nil {
		fmt.Println("key does not exists")
		return
	}
	panic(err)
}
fmt.Println(val.(string))

Do() 方法返回 Cmd 类型,你可以使用它获取你想要的类型:

Go 复制代码
// Text is a shortcut for get.Val().(string) with proper error handling.
val, err := rdb.Do(ctx, "get", "key").Text()
fmt.Println(val, err)

方法列表:

Go 复制代码
s, err := cmd.Text()
flag, err := cmd.Bool()

num, err := cmd.Int()
num, err := cmd.Int64()
num, err := cmd.Uint64()
num, err := cmd.Float32()
num, err := cmd.Float64()

ss, err := cmd.StringSlice()
ns, err := cmd.Int64Slice()
ns, err := cmd.Uint64Slice()
fs, err := cmd.Float32Slice()
fs, err := cmd.Float64Slice()
bs, err := cmd.BoolSlice()

redis.Nil

redis.Nil 是一种特殊的错误,严格意义上来说它并不是错误,而是代表一种状态,例如你使用 Get 命令获取 key 的值,当 key 不存在时,返回 redis.Nil。在其他比如 BLPOPZSCORE 也有类似的响应,你需要区分错误:

Go 复制代码
val, err := rdb.Get(ctx, "key").Result()
switch {
case err == redis.Nil:
	fmt.Println("key不存在")
case err != nil:
	fmt.Println("错误", err)
case val == "":
	fmt.Println("值是空字符串")
}

Conn

redis.Conn 是从连接池中取出的单个连接,除非你有特殊的需要,否则尽量不要使用它。你可以使用它向 redis 发送任何数据并读取 redis 的响应,当你使用完毕时,应该把它返回给 go-redis,否则连接池会永远丢失一个连接。

Go 复制代码
cn := rdb.Conn(ctx)
defer cn.Close()

if err := cn.ClientSetName(ctx, "myclient").Err(); err != nil {
	panic(err)
}

name, err := cn.ClientGetName(ctx).Result()
if err != nil {
	panic(err)
}
fmt.Println("client name", name)

连接池大小

go-redis 底层维护了一个连接池,不需要手动管理。默认情况下, go-redis 连接池大小为 runtime.GOMAXPROCS * 10,在大多数情况下默认值已经足够使用,且设置太大的连接池几乎没有什么用,可以在 配置项 中调整连接池数量:

Go 复制代码
rdb := redis.NewClient(&redis.Options{
    PoolSize: 1000,
})

超时

如果你使用 context.Context 处理超时,但也不要禁用 DialTimeout 、ReadTimeout 和 WriteTimeout ,因为 go-redis 会在不使用 context.Context 的情况下执行一些后台检查,这些检查依赖这些超时配置项。

请注意:net.Conn 依赖 Deadline 而不是 ctx 。

context.Context 的超时时间不要设置太短,因为当 context.Context超时,连接池无法确认连接是否还能正常使用,后面可能还会接收到数据,这样的连接不能被复用,只能丢弃并打开新的网络连接。在网络出现缓慢、丢包、redis 服务器执行消耗过多时间时, 将出现大量连接被丢弃、新建连接,这样连接池也就失去了意义,且情况会越来越恶化。

你可以查看 Go Context timeouts can be harmful (英文版) 这篇文章了解更多。

context 是一种控制超时的方式,但并不是所有场景都适用它。

Lua 脚本

Go 复制代码
var incrBy = redis.NewScript(`
local key = KEYS[1]
local change = ARGV[1]

local value = redis.call("GET", key)
if not value then
  value = 0
end

value = value + change
redis.call("SET", key, value)

return value
`)

运行脚本

Go 复制代码
keys := []string{"my_counter"}
values := []interface{}{+1}
num, err := incrBy.Run(ctx, rdb, keys, values...).Int()

Lua 和 Go 类型

下面是 Lua 和 Go 语言的类型对照表,Lua 的 number 是一个浮点型数字,用于存储整数和浮点数,在 Lua 中不区分整数和浮点数,但 Redis 总是将 Lua 数字转换为舍去小数部分的整数,例如 3.14 变成 3,如果要返回浮点值,将其作为字符串返回并用 Go 解析成 float64。

Lua return Go interface{}
number (float64) int64 (舍弃小数)
string string
false redis.Nil error
true int64(1)
{ok = "status"} string("status")
{err = "error message"} errors.New("error message")
{"foo", "bar"} []interface{}{"foo", "bar"}
{foo = "bar", bar = "baz"} []interface{}{} (不支持)

更多探索

官网:Golang Redis客户端

相关推荐
Tttian62215 分钟前
基于Pycharm与数据库的新闻管理系统(2)Redis
数据库·redis·pycharm
言之。1 小时前
redis延迟队列
redis
hanbarger2 小时前
nosql,Redis,minio,elasticsearch
数据库·redis·nosql
弗罗里达老大爷2 小时前
Redis
数据库·redis·缓存
别这么骄傲3 小时前
lookup join 使用缓存参数和不使用缓存参数的执行前后对比
缓存
007php00712 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
海海不掉头发15 小时前
苍穹外卖-day05redis 缓存的学习
学习·缓存
川石教育16 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存
DT辰白17 小时前
基于Redis的网关鉴权方案与性能优化
数据库·redis·缓存
木子七18 小时前
Redis-十大数据类型
redis