Redis®*: 实时排名用户
学习如何使用 Redis 实时为 200 万用户按分数排名
👋 欢迎来到 Stackhero 文档!
Stackhero 提供即用型 Redis 云 解决方案,带来众多优势,包括:
- 包含
Redis Commander网页界面。- 无限消息大小和传输。
- 只需点击即可轻松更新。
- 由私有和专用 VM提供的最佳性能和强大安全性。
节省时间,简化生活:只需 5 分钟即可试用 Stackhero 的 Redis 云托管 解决方案!
我们的一个客户提出了一个有趣的挑战。他运营一个体育网站,用户在赢得赌注或完成各种操作时可以获得积分。
他的目标是显示每个用户的排名,展示他们上下的用户,并生成前 100 名的排行榜。拥有 200 万用户的社区,数据需要实时处理!
在 Stackhero,我们喜欢解决这样的挑战。在本文中,我们将逐步引导您了解我们的解决方案。
为什么选择 Redis
传统数据库如 MySQL、PostgreSQL 或 Elasticsearch 并非为低延迟排名任务设计。这促使我们探索其他选项。
我们选择了 Redis,这是一种极快且可靠的内存数据库。根据 DB-Engines,它是全球第七大使用最广泛的数据库,并在“键值存储”类别中处于领先地位。
Redis 提供多种数据模型。在这种情况下,“有序集合”尤为突出。
技术验证
有序集合结合了键和分数。在我们的案例中,键是用户 ID,分数代表用户的积分。
我们首先启动了一个 Stackhero 上的 Redis 服务。该服务在 2 分钟内即可使用最新稳定版本上线,提供按小时计费,并配有 Redis Commander,一个方便的网页 GUI。我们使用此界面验证了概念。
我们添加了三个示例 ID 和分数的用户,如下所示:
| 用户名 | 分数 | | - | - | | userId1 | 11 | | userId2 | 54 | | userId3 | 24 |
这些用户通过以下 Redis 命令被添加到一个名为 usersScores 的有序集合中:
ZADD usersScores 11 "userId1"
ZADD usersScores 54 "userId2"
ZADD usersScores 24 "userId3"
Redis Commander,Stackhero 提供的 Redis 实例的网页 GUI
接下来,我们检索了 userId1 的分数:
ZSCORE usersScores "userId1"
> 11
这确认了 userId1 的分数确实是 11。之后,我们检查了 userId1 的排名:
ZREVRANK usersScores "userId1"
> 2
请记住,排名从 0 开始。这意味着排名如下:
| 用户名 | 分数 | 排名 | | - | - | - | | userId1 | 11 | 2 | | userId2 | 54 | 0 | | userId3 | 24 | 1 |
命令 ZREVRANK 返回了 2,这正是我们对 userId1 的预期。
您还可以获取前几名。例如,要检索前 2 名用户(从排名 0 到排名 1),请运行:
ZREVRANGE usersScores 0 1 WITHSCORES
> 1) userId2
> 2) 54
> 3) userId3
> 4) 24
要获取前 100 名用户,只需运行:
ZREVRANGE usersScores 0 99 WITHSCORES
这种方法高效且非常适合高性能实时排名。
其他有用的命令
以下是我们客户网站上使用的一些其他 Redis 命令:
- 获取排名在 50 到 100 之间的用户:
ZREVRANGE usersScores 50 100 WITHSCORES - 添加用户:
ZADD usersScores 40 "userId4" - 更新用户分数(这将替换现有的
userId4条目):ZADD usersScores 42 "userId4" - 删除用户:
ZREM usersScores "userId4"
使用 Node.js 的 Redis 代码示例
在 Redis Commander 中验证概念后,是时候将 Redis 集成到实际代码中了。我们的客户使用 Node.js,以下是使用 ioredis 作为客户端的示例:
const Redis = require('ioredis');
(async () => {
// 设置 Redis 凭证
// 如果您使用 Stackhero,您将在 Stackhero 仪表板上找到这些
const redis = new Redis({
host: '<redisServerHost>',
password: '<redisServerPassword>',
port: <PORT_TLS>, // <PORT_CLEAR> 用于非加密连接,<PORT_TLS> 用于 TLS。应使用 TLS。
tls: {}, // 提供一个空对象以激活 TLS
lazyConnect: true
});
// 连接到 Redis
await redis.connect();
// 添加用户
await redis.zadd('usersScores', 11, 'userId1');
await redis.zadd('usersScores', 54, 'userId2');
await redis.zadd('usersScores', 24, 'userId3');
// 检索 userId1 的分数
const score = await redis.zscore('usersScores', 'userId1');
console.log('userId1 有 ' + score + ' 分');
// 检索 userId1 的排名位置
const rankPosition = await redis.zrevrank('usersScores', 'userId1');
console.log('userId1 排名在位置 ' + rankPosition);
// 从 Redis 断开连接
await redis.disconnect();
})();
这个简单而强大的代码片段非常适合管理实时排名数据。
结论
解决这个问题既有趣又具有挑战性。在我们的案例中,Redis 被证明是一个理想的解决方案,因为它易于使用、功能强大且速度极快。
如果您想尝试 Redis,您可以在 Stackhero 上在 2 分钟内启动一个实例。享受最新稳定版本、网页 GUI、备份和令人印象深刻的性能,触手可及。
Stackhero 仪表板显示正在运行的 Node.js 和 Redis 服务