Redis 不是簡單的 key-value 緩存,它更像一把“瑞士軍刀”。
只要掌握數據結構,就能把同一份內存用出 10 倍效率。
0. 開場白:為什么聊數據結構?
面試常問“Redis 有幾種數據類型?”——很多人答 5 種(String、List、Hash、Set、ZSet)。
但 Redis 7.0 源碼里已出現 9 種編碼(encoding),未來還會更多。
理解“類型 vs 編碼”是區分菜鳥與專家的第一步。
對外類型(type) | 內部可能編碼(encoding) | 場景關鍵字 |
---|---|---|
string | int、embstr、raw、sdshdr5… | 計數器、緩存 |
list | ziplist、quicklist | 消息隊列 |
hash | ziplist、hashtable | 對象緩存 |
set | intset、hashtable | 去重、抽獎 |
zset | ziplist、skiplist | 排行榜 |
stream | rax + listpack | Kafka-lite |
bitmap / hyperloglog / geo | 特殊緊湊編碼 | 大數據去重、LBS |
下面按使用頻率由淺入深展開。
1. String:最被低估的“全能選手”
- 底層:簡單動態字符串(SDS),預分配策略減少 80% 內存重分配。
- 三大絕技
- 緩存:SET / GET 常規操作。
- 計數器:INCR、INCRBY 原子自增,秒殺庫存必備。
- 分布式鎖:SET key value NX PX 30000 一條命令解決“SETNX + EXPIRE”非原子問題。
- 面試題:為什么 512 MB 以下都用 embstr?
答:embstr 將 redisObject 與 SDS 連續分配,一次 malloc,CPU cache 友好。
2. List:雙端隊列 & 阻塞隊列
- 編碼進化史:ziplist(<=3.2) → quicklist(4.0) → listpack(7.0)。
- 典型用法
- 棧:
LPUSH + LPOP
- 隊列:
RPUSH + LPOP
- 阻塞隊列:
BLPOP mylist 0
(0 表示永不超時)
- 棧:
- 坑:ziplist 轉 quicklist 的閾值
list-max-ziplist-size -2
,負值表示節點字節限制。
3. Hash:小對象之王
- 閾值:hash-max-ziplist-entries 512 / hash-max-ziplist-value 64。
小 Hash 用 ziplist,大 Hash 自動轉 hashtable,O(1) vs O(N) 差異巨大。 - 實戰:
單 key 管理對象字段,比多個 String 省內存 30%+。HSET user:1001 name kim age 18 HINCRBY user:1001 age 1
4. Set:無序去重 + 數學集合
- 編碼:全整數且元素 ≤ set-max-intset-entries 512 → intset,否則 hashtable。
- 花式用法
- 抽獎:
SRANDMEMBER lucky 1
隨機 1 人 - 交并差:
SINTER tag:redis tag:cache
找出共同標簽的文章。
- 抽獎:
5. Sorted Set:排行榜 & 延遲隊列
- 底層:skiplist + dict 雙索引,O(logN) 范圍查詢 + O(1) 成員定位。
- 排行榜
ZINCRBY rank:2025 1 player:42 ZREVRANGE rank:2025 0 9 WITHSCORES
- 延遲隊列:score 存執行時間戳,用
ZRANGEBYSCORE
定時輪詢即可。
6. Stream:Redis 的 Kafka
- 組成:
- 消息:
XADD mystream * field value
- 消費組:
XGROUP CREATE mystream g1 $
- 消息:
- 特點:
- 消息持久化,重啟不丟。
- 支持 ACK、PEL(pending list),比 List 做隊列更可靠。
7. 三大“特種類型”
類型 | 命令示例 | 用途 |
---|---|---|
Bitmap | SETBIT uv:20250801 10086 1 | 日活統計(1 bit/用戶) |
HyperLogLog | PFADD ip:20250801 1.1.1.1 | 去重計數,誤差 < 0.81% |
Geo | GEOADD shops 116.397 39.909 “beijing” | 附近 5 km 門店 |
8. 內存優化 3 板斧
- 編碼對齊:
DEBUG OBJECT key
看 encoding,針對性調閾值。 - 壓縮:開啟
list-compression-depth 2
對中間節點壓縮。 - 短結構:小數據量用 ziplist/listpack,可把內存壓到 1/8。
9. 小結與思維導圖
Redis 數據結構 = 對外類型 + 內部編碼 + 閾值參數↓用對結構,省內存,提性能