Redis®*: 即時排名用戶

學習如何使用 Redis 即時為 200 萬用戶按分數排名

👋 歡迎來到 Stackhero 文件!

Stackhero 提供即用型的 Redis cloud 解決方案,帶來多項優勢,包括:

  • 包含 Redis Commander 網頁介面
  • 無限制的訊息大小和傳輸。
  • 只需點擊即可輕鬆完成 更新
  • 專用私有 VM 提供的最佳 效能和強大 安全性

節省時間簡化您的生活:只需 5 分鐘即可嘗試 Stackhero 的 Redis cloud hosting 解決方案!

我們的一位客戶提出了一個有趣的挑戰。他經營一個體育網站,當用戶贏得賭注或完成各種操作時,他們會獲得積分。

他的目標是顯示每個用戶的排名,展示他們上下的用戶,並生成前 100 名排行榜。擁有 200 萬用戶的社群,數據需要即時處理!

在 Stackhero,我們喜歡應對這樣的挑戰。在本文中,我們將逐步引導您了解我們的解決方案。

傳統數據庫如 MySQLPostgreSQLElasticsearch 並非為低延遲排名任務設計。這促使我們探索其他選擇。

我們選擇了 Redis,這是一個極快且可靠的內存數據庫。根據 DB-Engines,它是全球第七大使用最廣泛的數據庫,也是 "Key-value store" 類別中的領先選擇。

Redis 提供多種數據模型。對於這個場景,一個模型脫穎而出:"sorted sets"。

Sorted sets 結合了鍵和分數。在我們的情況下,鍵是用戶 ID,分數代表用戶的積分。

我們開始啟動 Stackhero 上的 Redis 服務。該服務在 2 分鐘內即可啟動,提供最新穩定版本,按小時計費,並配有 Redis Commander,一個方便的網頁 GUI。我們使用此界面驗證了概念。

我們添加了三個用戶,示例 ID 和分數如下所示:

| 用戶名 | 分數 | | - | - | | userId1 | 11 | | userId2 | 54 | | userId3 | 24 |

這些用戶使用以下 Redis 命令添加到名為 usersScores 的 sorted set 中:

ZADD usersScores 11 "userId1"
ZADD usersScores 54 "userId2"
ZADD usersScores 24 "userId3"

Redis Commander,Stackhero 上提供的 Redis 實例的網頁 GUIRedis 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"

在 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 服務Stackhero 儀表板顯示正在運行的 Node.js 和 Redis 服務