前言
游戏排行榜是一个常见需求,今天主要介绍go语言使用redis-sort-sets来实现排行榜常见功能。
Redis Sort Sets
官方介绍:
Redis排序集是按相关分数排序的惟一字符串(成员)的集合。当多个字符串具有相同的分数时,字符串将按字典顺序排列。排序集的一些用例包括:
游戏排行榜。例如,您可以使用排序集轻松地维护大型在线游戏中最高分数的有序列表。 速率限制器。特别是,您可以使用一个排序集来构建滑动窗口速率限制器,以防止过多的API请求。
常用于排行榜的命令:
- ZRANGE 返回排序集的成员(升序)
- ZREVANGE 返回排序集的成员(降序序)
- ZADD 向排序集添加一个新成员和相关分数。如果成员已经存在,则更新评分。
- ZREM 删除排序集一个成员
- ZRANK 返回提供的成员的排名(升序)
- ZREVRANK 返回提供的成员的排名(降序)
Go Redis
Go Redis为各种风格的Redis提供Go客户端,基础的使用例子如下:
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v9"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // use default Addr
Password: "", // no password set
DB: 0, // use default DB
})
pong, err := rdb.Ping(ctx).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(pong, err)
if err != nil {
fmt.Println(err)
return
}
defer rdb.Close()
}
Examples
这里我们用go-redis实现排行榜常见的功能,包括:
- 获取排行榜成员和分数 (升序、降序)
- 加入排行榜成员
- 删除排行榜成员
- 更新排行榜成员分数
- 获取排行榜成员分数
- 获取排行榜名次成员
- 清空排行榜
完整代码如下:
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v9"
"math/rand"
"strconv"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // use default Addr
Password: "", // no password set
DB: 0, // use default DB
})
var err error
defer rdb.Close()
//增加玩家分数的变化
for i := 1; i <= 5; i++ {
err = rdb.ZAdd(ctx, "leaderboard", redis.Z{
Score: float64(rand.Intn(100)),
Member: "user:" + strconv.Itoa(i),
}).Err()
if err != nil {
fmt.Println(err)
return
}
}
if err != nil {
fmt.Println(err)
return
}
//查询排行榜成员-升序
members, err := rdb.ZRange(ctx, "leaderboard", 0, 5).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("查询排行榜成员-升序", members)
//查询排行榜成员和分数-升序
membersWithScore, err := rdb.ZRevRangeWithScores(ctx, "leaderboard", 0, 5).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("查询排行榜成员和分数-升序", membersWithScore)
//查询排行榜成员-降序
membersRev, err := rdb.ZRevRange(ctx, "leaderboard", 0, 5).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("查询排行榜成员-降序", membersRev)
//查询排行榜成员和分数-升序
membersRevWithScore, err := rdb.ZRangeWithScores(ctx, "leaderboard", 0, 5).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("查询排行榜成员和分数-升序", membersRevWithScore)
//获取某玩家的分数
user2Score, err := rdb.ZScore(ctx, "leaderboard", "user:2").Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("获取某玩家 user:2 的分数", user2Score)
//更新某玩家的分数
err = rdb.ZAdd(ctx, "leaderboard", redis.Z{
Score: user2Score,
Member: "user:1",
}).Err()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("更新某玩家 user:1 的分数", user2Score)
//查询排行榜成员和分数-升序
membersRevWithScore, err = rdb.ZRangeWithScores(ctx, "leaderboard", 0, 5).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("查询排行榜变化后的排行榜成员和分数-升序", membersRevWithScore)
//查询排行榜某玩家的分数-升序
memberRank, err := rdb.ZRank(ctx, "leaderboard", "user:2").Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("查询排行榜某玩家 user:2 的排名", memberRank)
//查询排行榜某玩家的分数-降序
memberRevRank, err := rdb.ZRevRank(ctx, "leaderboard", "user:2").Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("查询排行榜某玩家 user:2 的排名-降序", memberRevRank)
//删除排序集一个成员
zrem, err := rdb.ZRem(ctx, "leaderboard", "user:1").Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("删除排序集一个成员", zrem)
//删除后查询排行榜成员-升序
members, err = rdb.ZRange(ctx, "leaderboard", 0, 5).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("删除后查询排行榜成员-升序", members)
//清空排行榜
clear, err := rdb.ZRemRangeByRank(ctx, "leaderboard", 0, 4).Result()
if err != nil {
fmt.Println("err zrem", err)
return
}
fmt.Println("清空排行榜", clear)
//清空后查询排行榜成员-升序
members, err = rdb.ZRange(ctx, "leaderboard", 0, 5).Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("清空后查询排行榜成员-升序", members)
OutPut:
查询排行榜成员-升序 [user:3 user:4 user:1 user:5 user:2]
查询排行榜成员和分数-升序 [{87 user:2} {81 user:5} {81 user:1} {59 user:4} {47 user:3}]
查询排行榜成员-降序 [user:2 user:5 user:1 user:4 user:3]
查询排行榜成员和分数-升序 [{47 user:3} {59 user:4} {81 user:1} {81 user:5} {87 user:2}]
获取某玩家 user:2 的分数 87
更新某玩家 user:1 的分数 87
查询排行榜变化后的排行榜成员和分数-升序 [{47 user:3} {59 user:4} {81 user:5} {87 user:1} {87 user:2}]
查询排行榜某玩家 user:2 的排名 4
查询排行榜某玩家 user:2 的排名-降序 0
删除排序集一个成员 1
删除后查询排行榜成员-升序 [user:3 user:4 user:5 user:2]
清空排行榜 4
清空后查询排行榜成员-升序 []
参考
- 安装Redis https://redis.io/docs/getting-started/installation/
- Redis Sort Sets Docs https://redis.io/docs/data-types/sorted-sets/
- Go Redis https://github.com/go-redis/redis/v9