记录一下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
}