🎯 什麼情境該想到我
當你「Redis 平常很快、但偶爾出現一波延遲尖峰」,或是正要下一個作用在不知道多大的 key 上的指令的時候。
⚙️ 怎麼用(步驟 / 公式)
前提:「單執行緒」是指命令執行
Redis 6.0 起網路 I/O 已支援多執行緒,但命令執行仍然是單執行緒。兩個後果:
- ✅ 好處:單條命令天然原子,
INCR不需要鎖。 - ❌ 代價:所有命令排一條隊。任何一條
O(N)且 N 很大的命令,會讓後面所有請求一起等。
這不是「變慢」,是整台 Redis 在那段時間對所有 client 停止服務。監控上看到的是 p99 尖峰,不是平均值上升。
危險指令清單:複雜度裡有 N,而 N 你控制不了
| 指令 | 複雜度 | 替代做法 |
|---|---|---|
KEYS pattern | O(N),N = 整個 keyspace | SCAN cursor MATCH ... COUNT ...(游標分批) |
HGETALL / SMEMBERS | O(N),N = 集合大小 | HSCAN / SSCAN(自 2.8 起) |
ZRANGE key 0 -1 | O(log N + M),M = 全部 | 只取需要的區段;排行榜用 ZRANGE key 0 9 REV(ZREVRANGE 自 6.2 起已標為 deprecated,查證 2026-10-15) |
LRANGE key 0 -1 | O(N) | 取固定區段,並用 LTRIM key 0 99 控制長度上限 |
DEL bigkey | O(N),要同步釋放所有記憶體 | UNLINK(4.0 起):O(1) 回收 key,記憶體釋放丟到背景執行緒 |
FLUSHALL / FLUSHDB | O(N) | 加 ASYNC |
查證 2026-09-25:
UNLINK自 4.0.0 起提供,官方複雜度說明是「O(1) for each key removed regardless of its size,之後在另一個執行緒做 O(N) 的記憶體回收」。
注意lazyfree-lazy-user-del預設是關閉的(0),所以直接下DEL依然是同步釋放——想讓DEL自動走 lazy free,要自己開這個設定。
★ 偷 Redis 的心法:把一次大操作拆成很多次小操作
Redis 自己就是這樣解決「擴容 Hash 表要搬幾百萬個桶」的問題——漸進式 rehash:
- 字典內部同時保留兩張雜湊表(舊表 + 新表)。
- 不一次搬完。之後每次對這個字典做增刪改查時,順手搬一部分桶。
- 舊表清空後,rehash 完成。
代價是 rehash 期間要同時維護兩張表(查找要查兩次、記憶體暫時變高),換到的是單次阻塞時間被攤平。
這個心法比 Redis 本身通用得多:任何單執行緒/單一事件迴圈的環境(Node.js 的 event loop、Go 的單一 goroutine worker、瀏覽器主執行緒),遇到「一次要處理很多」都該想想能不能攤成很多次小的。
實務檢查清單
- 上線前問自己:這個 key 最大會長到多大? 沒有答案就不要用
HGETALL這類全取指令。 - 用
LTRIM/ZREMRANGEBYRANK主動封頂,別讓集合無限成長(例如只留最新 100 筆動態)。 - 開慢查詢日誌:
CONFIG SET slowlog-log-slower-than 10000(微秒),SLOWLOG GET看誰在拖。 - 掃 keyspace 一律用
SCAN家族,KEYS只在本機 debug 用。 - 刪大 key 用
UNLINK,或事先確認lazyfree-lazy-user-del已開。
🧪 我實際套用的紀錄
- 2026-09-25:(待填)
⚠️ 注意 / 什麼時候不適用
SCAN是弱保證:保證掃描期間全程存在的元素至少被回傳一次,但可能重複回傳,期間新增/刪除的元素則不保證。消費端要能容忍重複。UNLINK不是萬靈丹。它把釋放丟到背景,但如果 key 是巨大的 listpack/embstr 這類單一大塊分配,背景執行緒也只是一次free,省不了多少;真正有效的是成員數多的集合型 key。- 多執行緒 I/O 不會救你。6.0 的多執行緒只處理網路讀寫與協定解析,命令執行照樣排隊。
- Lua 腳本與
MULTI/EXEC期間是完全獨佔的,腳本裡寫迴圈掃大集合,等於自己造一個阻塞點。 - 這張卡談的是單一實例的阻塞,不涵蓋叢集的 slot 遷移、主從複製斷線這類問題。
🔗 相關工具
- 工具-Redis資料型別的底層編碼 — key 設計得好,N 就不會失控(大 key 的源頭治理)
- 工具-延遲任務方案選型 — Redis ZSet 延遲佇列的 worker 就是靠
LIMIT 0 1避免一次撈太多 - 工具-服務容錯設計 — Redis 卡住時,呼叫端要有逾時與降級,不能跟著一起死
- 工具-遙測與監控 — p99 尖峰要看得到,才會發現這類問題