「Redis 要不要上 Cluster?」這種問題我沒辦法直接回答,因為它問錯了。
Cluster、Sentinel、replica、讀寫分離——這四個東西常常被打包成一句「上 HA」,但它們解的是四個不同的問題。選錯的代價不對稱:你只是怕它掛掉,卻上了 Cluster,換來的是一整套分片運維的複雜度,去解一個你根本沒有的問題。
比較有用的問法是:你撞到的是哪一堵牆?
牆 0:怕重啟就沒了
這堵牆是 Redis 特有的,DB 天生免疫。
Redis 資料在記憶體裡,進程一重啟就空了。所以它需要 RDB(定期快照)或 AOF(追加寫入日誌),或兩者混用。關聯式資料庫沒有這個問題——WAL(write-ahead log)本來就是它的基本結構,每一筆寫入落地之前先進 log,crash 之後照 log 重放。
這堵牆跟高可用一點關係都沒有,但它常常被混進去講。一台 Redis 開了 AOF,它還是一台會掛的 Redis;你只是保證它掛完再爬起來時資料還在。
牆 1:怕它死掉(可用性)
這才是「HA」三個字真正在講的東西。而這裡有一個最常見的誤會:
Replication 給你的是副本,不是高可用。
先把三個詞講白:replication 是「把主要那台的資料持續複製到另一台」;被寫入的那台叫 primary(主庫),跟著複製的那台叫 replica(副本);而 failover 是「主庫掛了,讓副本頂上」這整套動作。
問題就出在第三個。你開了一台 replica,資料是同步過去了,但 primary 掛掉的那一刻,誰來決定 replica 升格?誰去通知客戶端改連新的位址?沒有人——有副本沒有 failover 機制,等於半夜三點你自己爬起來手動切。
所以這堵牆要兩個東西一起才算翻過去:
- replication — 資料有副本
- failover 機制 — Redis 是 Sentinel,PostgreSQL 是 promote 流程。它負責偵測、選出接手的那台、讓客戶端跟著改連
我自己在 express-rabbitmq 那個可靠性實驗場裡實測過兩邊:Redis 那條跑 Sentinel promote,觀察客戶端有沒有跟著轉;DB 那條跑 PostgreSQL promote,灌 20 筆資料驗證切換過程零丟失。驗過跟看過文件是兩件事——文件說會 failover,實測告訴你 failover 的那幾秒鐘客戶端是什麼反應。
牆 2:讀不夠用(讀擴展)
這堵牆有意思的地方在於:它的解法跟牆 1 是同一個東西的第二種用途。
你為了可用性開的那些 replica,反正資料都同步過去了,那就順便拿來分擔讀取——這就是讀寫分離。寫走 primary、讀走 replica。
代價是 lag。資料同步過去要時間,所以你會遇到「使用者剛改完資料,重新整理卻看到舊的」。這個情境有個名字叫 read-your-writes,處理方式是這類讀取指定回 primary,不要走 replica。
(讀寫分離在 DB 那邊的完整取捨——lag 怎麼量、哪些查詢該回 primary——寫在讀寫分離那篇。)
順帶一個我的觀察,但沒有實測數據支撐,當成推測聽就好:Redis 的讀寫分離比 DB 少用得多。我猜是因為 Redis 本來就快,讀不夠通常不是先撞到的牆——會先撞到的是下面那堵。
牆 3:裝不下、寫不動
前面三堵牆的解法都有一個共同前提:每台機器上都是完整的一份資料。
這個前提在兩種情況會破:資料大到單機記憶體/磁碟裝不下,或寫入量大到單一 primary 扛不住(因為寫入永遠只能走 primary,加 replica 完全不會提升寫入能力)。
這時候要的是 sharding——把資料切開,每台只負責一部分。
Redis Cluster 的做法是先把整個 key 空間切成 16384 個格子(官方叫 slot),每個 key 照名字算出它屬於哪一格,再把這些格子分配給不同機器。要加機器就搬幾格過去,不用重算全部。關聯式資料庫做同一件事叫分庫分表——同樣是「這筆資料該去哪一台」的分配問題,只是切的單位是資料表或資料庫。
關鍵是:sharding 跟 replication 是正交的兩件事。切成四個 shard 之後,每個 shard 內部還是需要自己的 replica 加 failover,不然任何一片掛掉就是那一段資料整個不見。Redis Cluster 之所以看起來「一次解決全部」,是因為它把牆 1 的機制內建進去了,不是因為它取代了牆 1。
所以 Cluster 不是 Sentinel 的進階版
這是整篇最想講的一句。
Sentinel 和 Cluster 常常被排成一條升級路線,好像 Sentinel 是入門版、Cluster 是專業版。但它們解的是不同的牆——Sentinel 解牆 1,Cluster 解牆 3(只是順手內建了牆 1)。
| 你的處境 | 該裝的 | 裝錯的代價 |
|---|---|---|
| 資料塞得下,但不能掛 | replication + Sentinel/promote | 上 Cluster:多一整套分片運維,解一個你沒有的問題 |
| 資料塞不下 or 寫不動 | sharding(Cluster/分庫分表)+ 每片自己的 replica | 只加 replica:寫入完全沒改善,因為寫永遠走 primary |
左邊那格是實務上更常見的處境,而它也是更常被裝錯的那一格。
這套框架可以搬
最後一件事,也是我覺得這個切法真正的價值:DB 和 Redis 撞的是同一組牆,只是工具名不同。
| 牆 | Redis | PostgreSQL |
|---|---|---|
| 0 重啟丟資料 | RDB / AOF | WAL(天生有) |
| 1 怕死 | replica + Sentinel | replica + promote |
| 2 讀不夠 | replica 分讀(較少用) | 讀寫分離 |
| 3 裝不下 / 寫不動 | Cluster slot 分片 | 分庫分表 |
換一個技術棧的時候,要搬的是這四堵牆的框架,不是工具名。
你去看訊息佇列(message broker,就是 RabbitMQ、Kafka 那類負責幫你把訊息暫存再轉交的中間人)也是同一套:訊息寫進磁碟免得重啟就沒了,是牆 0;多個節點各存一份、掛掉時推舉一台接手,是牆 1;把訊息分流到不同分區(Kafka 叫 partition,概念跟 Redis 的 slot 一樣,都是「這筆該歸哪一台管」)好讓單台不必扛全部,是牆 3。名字全都不一樣,牆是同一組。
記住牆,工具會自己對號入座。
相關
- 資料層運維全景 → 資料庫全景
- PostgreSQL 進階運維 → PostgreSQL 進階
- 讀寫分離的實作取捨 → DB 讀寫分離