Skip to content
Site Stats
總訪問量
訪客數人次

Redis 秒殺|手動索引、分頁與排行榜

上一篇 Worker 負責「取紙條、把帳記齊」。
打開那隻工具箱,裡面通常至少有四樣東西要補:

Stream 紙條Worker① 訂單本體② 用戶歷史③ 全域索引④ 排行榜

四樣東西用途不同:

要回答的問題補的是什麼
這張訂單內容是什麼?訂單本體
這個用戶買過哪些?用戶歷史
後台依時間翻頁怎麼翻?全域索引
哪個商品賣最好?排行榜

在 SQL 世界,很多關聯靠表格與索引自動維護。
在以 Redis 當主戰場的設計裡,這四樣常常要 Worker 寫入時自己維護——這就叫手動索引。下一拍起,我們逐個看它們長什麼樣子。

① 訂單本體:一張 key,一份內容

最直覺的一塊:訂單本體

  • Key 長得像門牌:order:訂單編號
  • Value 是這張訂單的完整內容(常見是一段 JSON 字串:誰買、買什麼、價格、時間…)
keyorder:o101value(訂單內容)用戶、商品、價格、時間…

你有門牌,就能直接把整張訂單拿出來——這很快。
但新問題來了:後台要「依時間列出第 3 頁」時,你不可能靠猜門牌。
所以才需要旁邊那些索引(②③④)幫你回答「有哪些 id、怎麼排序」。

② 用戶歷史:一條屬於某人的隊伍

「這個用戶買過哪些?」不需要每次掃全部訂單。
常見做法:每位用戶一條 List(列表),裡面只放訂單 id。

  • Key 像:user:小明:orders
  • 新訂單來時,把 id 塞到隊伍最前面(最新的在前)
user:小明:orderso103o101o077← 越左邊越新 只要 id,細節再去 order:… 拿

List 回答的是「有哪些門牌、大概的先後」。
真正的訂單內容,還是回到 ① 用門牌去取——索引薄、本體厚,各做各的事。

③ 全域索引:ZSet 當時間軸

後台要「依時間翻頁看全部訂單」時,需要一條全站共用的時間軸
Redis 的 ZSet(有序集合) 很適合:每個成員是訂單 id,旁邊掛一個分數(score)——這裡用時間戳

orders:index(示意)o103score 較新o101score …o077score …更早翻頁=從時間軸上切一段 id,再去拿訂單本體

翻第 1 頁、第 3 頁,本質都是:在時間軸上切一段 id 出來
不要對整庫做「把所有訂單門牌掃一遍」——那是另一種轉圈圈。

有了 id 列表之後,再一次把對應的訂單本體撈回來(下一節就講這兩步怎麼配)。

④ 排行榜:還是 ZSet,分數換成銷量

「哪個商品最好賣?」——又是排序問題。
於是排行榜也常用 ZSet:成員換成商品 id,分數換成銷量(或累計金額,看你怎麼定義「熱」)。

leaderboard:sales(示意)商品 Ascore 最高商品 Cscore …商品 Bscore …Worker 每成功一筆,就給對應商品的分數 +1(或加金額)

同一種籃子,兩種用法:

用途成員是誰分數代表什麼
全域訂單索引訂單 id時間
熱銷排行榜商品 id銷量/熱度

不需要每次用 SQL 掃表再 ORDER BY——分數更新時,排序關係已經在 ZSet 裡。

兩步讀法:先門牌,再一次拿內容

無論是用戶歷史(List)還是後台時間軸(ZSet),讀法都差不多:

  1. 先從索引拿到一串訂單 id
  2. 再依這串 id,一次把多份訂單本體撈回來
① 索引o103, o101, o077② 批次讀一次拿多份本體畫面要的資料三張訂單內容索引保持輕薄;重的 JSON 只在需要顯示時才取

為什麼不把整包 JSON 塞進索引?
因為同一份訂單會出現在「用戶歷史」和「全域時間軸」——本體存一份就好,索引只負責指路。批次讀(常對應一次拿多個 key)就是把路牌變成內容的那一步。

刪除時要掃乾淨

手動索引的代價是:你寫了幾份,刪的時候也要記得幾份。

只刪 order:o101 本體,卻忘掉:

  • 全域時間軸上的 o101
  • 某用戶 List 裡的 o101

後台翻頁就會點到幽靈門牌——有索引、沒內容。

刪除訂單 o101清本體清時間軸清用戶 List

實務上會把這些刪除綁成一次事務/一次腳本,避免清到一半失敗。細節見專案後台刪除流程:redis-seckill

本篇小结(與系列收束)

📝 TL;DR:Worker 用手動索引維護本體、用戶歷史、時間軸、排行榜;讀資料是「先 id 再批次拿本體」;刪除要連索引一起清。

你帶走四件事:

  1. 本體一份、索引多份 — String 存內容;List/ZSet 負責指路與排序。
  2. ZSet 兩用 — 分數=時間做分頁;分數=銷量做排行榜。
  3. 兩步讀 — 索引給 id,再一次取多份本體。
  4. 刪要掃乾淨 — 否則幽靈門牌。

三篇地圖

檔案記住什麼
1redis-seckill-intro轉圈圈、Redis 第一線、又快又不能算錯
2redis-seckill-streams原子扣減、Stream 削峰、Worker
3本篇手動索引、分頁、排行榜、刪除一致性

尚可繼續探索(專案 README 也有提):Worker 失敗時的重試、死信、庫存回補——那是「紙條丟了怎麼辦」的下一層。
完整實作:lucashsu95/redis-seckill