System Design·2026年6月1日·11 分鐘閱讀

Redis 在我的系統裡的幾種用法:快取、分散式鎖、排行榜

L
Louis Wu

後端工程師,在高併發與金流系統裡大量使用 Redis。

很多人對 Redis 的印象停在「一個很快的快取」。它確實是,但在我做的高併發系統裡,Redis 扮演的角色遠不只如此。這篇講我實際用 Redis 的幾種方式、各自要注意什麼,以及那些「用錯會出大事」的細節。

一、快取:最常見,但魔鬼在失效

快取是 Redis 最基本的用途:把昂貴的查詢結果存起來,下次直接拿,省掉資料庫的負擔。簡單,但真正難的從來不是「存」,是「什麼時候讓它失效」。

我踩過的坑:

  • 快取與資料庫不一致:資料更新了,但快取還是舊的。我的原則是更新資料時主動讓對應的快取失效,而不是傻等它過期
  • 快取雪崩:大量 key 同時過期,請求瞬間全打到資料庫把它壓垮。解法是讓過期時間帶一點隨機,錯開失效時間
  • 快取穿透:一直查一個根本不存在的 key,每次都繞過快取打到資料庫。解法是連「不存在」這件事也快取起來(存一個空值短時間)

快取講起來簡單,但這幾個失效情境沒處理好,它反而會變成壓垮系統的那根稻草。

二、分散式鎖:跨服務的互斥

當你有多台機器、多個程序,要確保「同一件事同一時間只有一個人在做」(例如同一張訂單不要被兩個 worker 同時處理),就需要分散式鎖。Redis 常被拿來做這個。

關鍵細節,每一個都很重要:

  • 鎖一定要設過期時間:拿到鎖的程序如果當掉了卻沒釋放,這把鎖就永遠鎖死。設過期時間是保命的
  • 解鎖要驗身分:你只能釋放「自己拿的」那把鎖。每次上鎖帶一個唯一識別,解鎖時先確認是自己的才放,否則可能誤放別人的鎖
  • 過期時間要抓準:設太短,工作還沒做完鎖就過期,別人就進來了,等於沒鎖;設太長,當掉之後要等很久才釋放

分散式鎖看起來簡單,但這些細節錯一個,鎖就形同虛設。在金流場景,「鎖沒鎖住」可能就是重複扣款。

三、原子計數與庫存扣減

Redis 的單執行緒特性讓它的單一指令天然是原子的,這在搶購系統裡超好用。前面我寫搶購系統時提過:用 Lua script 把「檢查庫存大於 0 就遞減」包成一個原子操作,就能在記憶體裡安全地扣庫存,扛住瞬間高併發,完全不碰資料庫。

重點是原子性:判斷和扣減必須是不可分割的一步,否則併發下一定超賣。

四、排行榜:sorted set 的主場

即時排行榜(積分榜、熱門排序)用關聯式資料庫做會很吃力——每次都要排序一大堆資料。Redis 的 sorted set 天生就是為這個設計的:每個成員帶一個分數,自動依分數排序,查「前 N 名」「某人的排名」都是高效操作。更新分數、即時反映排名,順手得很。

五、限流

Redis 也常拿來做限流的計數器——用它的原子遞增配上過期時間,記錄「某使用者在這段時間內請求了幾次」,超過就擋。因為是集中式的,多台機器共用同一份計數,限流才準。限流我之後有專門一篇細講。

別忘了:Redis 是記憶體,資料會掉

最後一個心態上的提醒:Redis 主要活在記憶體裡。雖然有持久化機制,但它的定位不是「絕對不能掉資料的主資料庫」。我的原則是:真正的事實來源放在資料庫,Redis 放的是可以重建的東西(快取、可重算的計數、即時排名)。萬一 Redis 掉了,系統要能從資料庫重建,而不是直接損失關鍵資料。

小結

Redis 在我的系統裡的角色:

  • 快取:重點是失效策略,小心雪崩與穿透
  • 分散式鎖:一定要過期、解鎖要驗身分、過期時間抓準
  • 原子扣庫存:用 Lua script 保證原子性,扛搶購
  • 排行榜:sorted set 的主場
  • 限流:集中式計數器
  • 心態:Redis 放可重建的東西,事實來源在資料庫

Redis 很強,但它的每一種用法都有「用錯會出事」的細節。把這些細節摸熟,它就是你高併發系統裡最可靠的夥伴之一。

#Redis#快取#分散式鎖#高併發#系統設計

相關文章