先猜猜看,你身邊講到 Redis,十個有九個第一句是什麼?

「喔那個放快取的嘛。」

對,但這就像說「手機是拿來打電話的」一樣——沒講錯,可是少講了 90%。Redis 確實超會當快取,但你要是只拿它做這件事,等於買了把瑞士刀只拿來開瓶蓋。這篇就帶你看看刀子上其他那些刀片。


它到底是什麼

Redis 是一個把資料放在記憶體裡的資料庫,而且它存的不是死板的字串,是「有結構」的東西。

兩個重點。第一個「記憶體」,這就是它快的原因——資料不在硬碟、不用繞一大圈,直接在 RAM 裡拿,一次操作通常零點幾毫秒就回你。

第二個重點才是真正讓 Redis 與眾不同的地方:它懂資料結構。它不只會存「key = 一串字」,它還會存:

  • List——一條串列,可以從兩頭塞、兩頭拿(拿來做簡單佇列剛好)
  • Set——一包不重複的東西(誰按過讚、誰在線上)
  • Sorted Set——會自動照分數排好的 set(排行榜本人)
  • Hash——一個 key 底下掛一堆欄位(像存一個物件)
  • String / 數字——還能原子地 +1(計數器、限流)

別人(例如老一輩的 Memcached)只會存字串,你要排行榜得自己撈出來排;Redis 直接內建一個會自己排序的結構給你。這就是 Redis 當年能起飛的關鍵——不是它比較快,是它把「資料結構」這件事帶進了快取層。


為什麼這些事不甘脆用 DB 做就好

你可能想說,排行榜、計數器,這些 MySQL 不是也能做嗎?能,但你做做看就知道有多痛。

排行榜:用 DB 就是 ORDER BY score DESC LIMIT 10。資料少還好,一旦榜上幾十萬人、又要即時更新分數、還每秒被查幾百次——這條 SQL 會把你的 DB 排序排到冒煙。Redis 的 Sorted Set 是塞進去的當下就排好了,查前十名跟查你自己的排名都是一瞬間。

限流(每個使用者每分鐘最多打 100 次 API):用 DB 你得「先查這分鐘打了幾次、再 +1、再寫回」,這中間還有併發問題要處理。Redis 一個 INCR 指令,原子地加一、順便回你現在的值,一行解決。

分散式鎖(兩台機器不能同時扣同一筆庫存):DB 的鎖只鎖得住「同一個 DB 連線裡的交易」,鎖不住「兩台不同機器同時跑」。Redis 一個 SET key value NX(不存在才設)就變成大家都看得到的共用鎖。

看出來了嗎?這些事 DB 不是不能做,是做起來又慢又彆扭。Redis 把這些變成內建的、原子的、一兩行就搞定的操作。所以它根本不只是快取——它是後端一堆「高頻小操作」的瑞士刀。


Redis 能幹的事,快速掃一遍

你想做的事用 Redis 的哪招
擋在 DB 前面減少重複查詢當快取(最常見)
API 限流、計數INCR 原子計數
即時排行榜Sorted Set
跨機器搶資源不打架分散式鎖(SET NX
存登入狀態Session store
輕量的任務佇列List / Streams

一張表你就懂為什麼大家說它是瑞士刀了。但瑞士刀不等於萬能,下一段講它的邊界。


它很快,但別把它當主資料庫

這是最多人栽跟頭的地方:Redis 又快又好用,用著用著就想「啊不然重要資料也存它好了」。千萬別。

理由很簡單——Redis 是記憶體優先的。記憶體的特性就是斷電即逝。雖然它有持久化機制(RDB 快照、AOF 日誌)能把資料備份到硬碟,但那是「盡量不掉」,不是「保證一筆都不掉」。極端情況下,最後那一小段還沒落地的寫入,是有可能跟著掉的。

所以心法是:主資料永遠放在 DB(那是真相來源),Redis 放的是「掉了還能從 DB 重建」的東西。 快取掉了?重新查一次 DB 回填就好。但你的訂單、金流、使用者資料這種「掉了會出大事」的,乖乖放 DB。

還有一個常被忘記的點:記憶體是有限又貴的。資料無腦往 Redis 塞、又不設過期,總有一天記憶體爆掉。所以一定要設 maxmemory 跟淘汰策略(最常用 allkeys-lru,記憶體滿了就把最久沒用到的踢掉)。

個人經驗:我自己最痛的一次,就是資料丟進 Redis 之後,跟 DB 的版本對不起來——而偏偏我們那段漏了做一致性的檢查。等到資料不一致真的爆出來,要回頭查「到底是哪一筆、從哪個環節開始歪掉的」,那個過程極度痛苦:快取跟 DB 兩邊都要對,還要還原當下的時序,根本像在驗屍。

這件事完全印證了那句老話——快取失效真的是兩大難題之一。教訓很簡單:東西丟進 Redis 的那一刻,就要同時想好「它什麼時候、靠什麼失效」,不然你省下的查詢時間,遲早會用加倍的 debug 時間還回去。


接下來往哪走

這篇想做的就是把你對 Redis 的印象,從「放快取的」升級成「後端瑞士刀」。再深的:


反思

Redis 之所以好用,是因為它把後端常常需要、但用 DB 做又很彆扭的那些小操作(計數、排序、上鎖、排隊),全部變成記憶體裡一兩行就解決的內建功能。

但「好用」很容易讓人用過頭。每次想把東西放 Redis 之前,問自己兩題:

  1. 這份資料掉了會怎樣?會出大事 → 它該待在 DB,Redis 頂多放它的快取。
  2. 我有沒有幫它設過期 / 設淘汰策略?沒有的話,你是在等記憶體某天爆掉。

把 Redis 當瑞士刀用,但別忘了它是把刀,不是保險箱。