Go中常用的Redis函数记录| 豆包MarsCode AI刷题

37 阅读4分钟

记录一下Golang中的Redis用法,方便以后查询。

1. 下载依赖

使用go get命令安装go-redis库:

go get github.com/go-redis/redis/v9

2. 创建Redis客户端实例

在使用之前,我们需要创建一个Redis连接。使用Options配置Redis服务器的地址、密码、数据库等参数:

func main() {
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379", // Redis服务器地址
        Password: "",              // Redis密码
        DB:       0,               // 使用的数据库
    })
    // 检查连接是否成功
    pong, err := rdb.Ping(context.Background()).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("Ping:", pong)
}

3. 基本操作

字符串操作

//获取匹配的key
val := rdb.Keys(context.Background(), "*").Val()
err := rdb.Set(context.Background(), "key", "value", 0).Err()
val, err := rdb.Get(context.Background(), "key").Result()

列表操作

// 将值推入列表
err := rdb.LPush(context.Background(), "list", "value1").Err()
// 从列表弹出值
val, err := rdb.RPop(context.Background(), "list").Result()

基于列表,我们可以实现一个简单的消息推送功能。

集合操作

// 添加元素到集合
err := rdb.SAdd(context.Background(), "set", "value1").Err()
// 获取集合中的所有元素
vals, err := rdb.SMembers(context.Background(), "set").Result()

有序集合操作

// 添加元素到有序集合
err := rdb.ZAdd(context.Background(), "zset", redis.Z{Score: 1, Member: "value1"}).Err()
// 获取有序集合中的元素
vals, err := rdb.ZRangeWithScores(context.Background(), "zset", 0, -1).Result()
for _, z := range vals {
    fmt.Printf("%s: %f\n", z.Member, z.Score)
}
//获取元素的排名
result := rdb.ZRank(context.Background(), "zset", "value1")
//获取元素的score
result := rdb.ZScore(context.Background(), "zset", "value1").Val()
//按score大小排序
result := rdb.ZRevRangeByScoreWithScores(context.Background(), "zset", &redis.ZRangeBy{
		Min: "-inf",
		Max: "+inf",
	})
for _, z := range result.Val() {
		fmt.Printf("Member: %s, Score: %.2f\n", z.Member, z.Score)
	}

位图

位图可以用于高效地处理二进制数据

val, err := rdb.GetBit(ctx, "mybitmap", 7).Result()
oldVal, err := rdb.SetBit(ctx, "mybitmap", 7, 1).Result()

HyperLogLog

HyperLogLog一般用于基数统计,可以用很小的空间就对数据进行计数,但是不能读取数据。

err := rdb.PFAdd(context.Background(), "hll", "value1", "value2").Err()
count, err := rdb.PFCount(context.Background(), "hll").Result()

Geo

存储地理位置信息,并进行查询。

//存储经纬度
err := rdb.GeoAdd(context.Background(), "ge", &redis.GeoLocation{
		Longitude: 104.0667, Latitude: 30.6667,
		Name: "chengdu",
	}).Err()
// 根据经纬度获取地理位置信息
locs, err := rdb.GeoPos(context.Background(), "ge", "chengdu").Result()

Streams

stream是redis中一个很厉害的数据结构,我们可以把它当做一个消息队列来使用

//消息写入
err := rdb.XAdd(context.Background(), &redis.XAddArgs{
			Stream: "mystream",
			Values: map[string]interface{}{
				"message": fmt.Sprintf("Hello %d", i),
			},
		}).Err()
// 创建消费组
err := rdb.XGroupCreateMkStream(context.Background(), "mystream", "mygroup", "0").Err()
//接受消息
streams, err := rdb.XReadGroup(context.Background(), &redis.XReadGroupArgs{
			Group:    "mygroup",
			Consumer: "consumer1",
			Streams:  []string{"mystream", ">"},//这里可以设置读取多个stream的消息,">"表示消费者应该从mystream流最新的未被当前消费组确认的消息开始读取。
			Count:    1,//每次读取多少条消息
			Block:    0,//在没有消息可读时应该等待的时间,0为永远阻塞
		}).Result()
//读取需要遍历所有的stream与message,因为可以从多个stream每个都可能接受多个message
for _, stream := range streams {
	for _, message := range stream.Messages {
// 确认消息处理,与消息队列一样,我们可以确认消息,让后续消费者消费后面的消息。
err = rdb.XAck(context.Background(), "mystream", groupName, message.ID).Err()

4. 实际使用

以上,就是redis的一些基本用法了,我们使用上述的的api来完成一些简单的功能实战一下

redis实现限流

我们拿redis做一个限流,利用它的原子操作我们可以确保并发环境下计数的准确性。我们以基于计数器的限流为例。基于计数器的限流是一种简单而常见的限流策略,通常用于控制对特定资源的访问频率

func allowRequest() bool {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "192.168.44.128:6379", // Redis服务器地址
		Password: "",                    // Redis密码(如果需要的话)
		DB:       4,                     // 使用的数据库
	})
	r := rdb.IncrBy(context.Background(), "counter", 1)
	num := r.Val()
	if r.Err() != nil || num >= 50 {
		return false
	}
	fmt.Print(num)
	if num == 1 {
		rdb.Expire(context.Background(), "counter", 10*time.Second)
	}
	return true
}

这样,我们就实现了一个简单了限流,每十秒限制请求数为50个。

redis实现布隆过滤器

我们拿redis做一个简单的布隆过滤器,可以用它来过滤掉一些未知的请求,我们用bitmap来实现它,来看看bitmap的api的使用

func bloomFilterSet(key string) {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "192.168.44.128:6379", // Redis服务器地址
		Password: "",                    // Redis密码(如果需要的话)
		DB:       4,                     // 使用的数据库
	})
	hash := sha256.Sum256([]byte(key))
	rdb.SetBit(context.Background(), "bloomfilter", int64(hash[0]), 1)
	rdb.SetBit(context.Background(), "bloomfilter", int64(hash[5]), 1)
	rdb.SetBit(context.Background(), "bloomfilter", int64(hash[10]), 1)
	rdb.SetBit(context.Background(), "bloomfilter", int64(hash[15]), 1)
	rdb.SetBit(context.Background(), "bloomfilter", int64(hash[20]), 1)
	rdb.SetBit(context.Background(), "bloomfilter", int64(hash[25]), 1)
	return
}
func bloomFilterGet(key string) bool {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "192.168.44.128:6379", // Redis服务器地址
		Password: "",                    // Redis密码(如果需要的话)
		DB:       4,                     // 使用的数据库
	})
	hash := sha256.Sum256([]byte(key))
	a := rdb.GetBit(context.Background(), "bloomfilter", int64(hash[0])).Val()
	a &= rdb.GetBit(context.Background(), "bloomfilter", int64(hash[5])).Val()
	a &= rdb.GetBit(context.Background(), "bloomfilter", int64(hash[10])).Val()
	a &= rdb.GetBit(context.Background(), "bloomfilter", int64(hash[15])).Val()
	a &= rdb.GetBit(context.Background(), "bloomfilter", int64(hash[20])).Val()
	a &= rdb.GetBit(context.Background(), "bloomfilter", int64(hash[25])).Val()
	return a == 1
}