本文是 Redis 鍵值設計的 14 個核心規范與最佳實踐,按重要程度分層說明:
一、通用數據類型選擇
這里我們先給出常規的選擇路徑圖。
以下是對每個步驟的分析:
- 是否需要排序?:
zset
(有序集合)用于排序的唯一值,而list
用于排序的重復值。
- 數據是否唯一?:
set
用于存儲唯一的值。
- 是否需要存儲對象?:
Hash
適合存儲對象或具有多個字段的結構。
- 考慮操作頻率?:
- String
和
Hash`都是Redis中最常用的數據類型,適用于高頻讀寫操作。
- String
- 數據大小和內存占用大?:
Bitmap
適合存儲大量數據,同時占用較少的內存。
- 消息隊列?:
stream
是Redis用于實現消息隊列的數據類型。
- 原子操作和數據過期?:
lua腳本
可以用于實現原子操作,而Redis的過期機制可以用于數據過期。
二、鍵設計規范(Key Design)
-
命名規范
- 格式:
業務模塊:數據維度:唯一標識
(例:user:profile:10001
) - 強制要求:禁止包含空格、換行符、不可見字符
- 建議:長度控制在 100 字節以內(內存敏感場景)
- 格式:
-
大Key規避
- 單Key值大小限制:
- String 類型 ≤ 10KB
- Hash/List/Set/Zset 元素數 ≤ 5000
- 超標處理方案:
- 數據分片(例:user:10001:cart_page1)
- 啟用壓縮(客戶端壓縮 + LZF Redis壓縮)
- 單Key值大小限制:
-
過期策略
- 必須設置過期時間(包括持久化數據,建議 30 天兜底)
- 不同過期時間策略:
-- 使用隨機過期時間避免批量過期導致的毛刺 local expire_time = 86400 + math.random(0, 3600) redis.call('EXPIRE', KEYS[1], expire_time)
三、值設計規范(Value Design)
-
數據結構選擇原則
- 按使用頻率選擇:
高頻讀寫 → String/Hash 范圍查詢 → ZSET 去重計算 → Set/HLL 關系查詢 → RedisGraph(需 4.0+)
- 禁止將 Redis 當關系型數據庫使用(避免復雜關聯查詢)
- 按使用頻率選擇:
-
JSON序列化陷阱
- 推薦方案:
- 高頻字段拆解為 Hash 字段
- 保留完整 JSON 作為 fallback 方案
- 優化案例:
HMSET user:10001 name "John" age 30 SET user:10001:full '{...}' EX 3600
- 推薦方案:
-
計數器設計
- 必須使用
INCR/DECR
代替GET+SET
- 集群環境推薦使用
INCRBY float
代替整數運算
- 必須使用
三、高級優化策略
-
內存優化技巧
- Hash 使用 ziplist 編碼:
redis.conf 配置: hash-max-ziplist-entries 512 hash-max-ziplist-value 64
- 使用
SSCAN/ZSCAN
替代SMEMBERS/ZRANGE
- Hash 使用 ziplist 編碼:
-
熱點Key治理
- 檢測方法:
redis-cli --hotkeys
- 解決方案:
- 本地緩存 + 異步刷新
- Key 分片(例:hotkey_v1 → hotkey:{shard_id}:v1)
- 檢測方法:
-
事務與管道
- 管道(pipeline)批量操作控制在 100 命令/批次
- Watch 事務中避免包含耗時操作
四、集群與持久化
-
集群規范
- 單個分片內存 ≤ 10GB(AWS 內存優化型實例)
- 跨槽操作使用 Hash Tag 需滿足:
- 相關Key必須使用相同{}內容
- 示例:
{user10001}.orders
,{user10001}.profile
-
持久化策略
- AOF 配置:
appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
- RDB 快照周期 ≥ 15 分鐘
- AOF 配置:
五、避坑指南
-
危險命令禁用
rename-command FLUSHALL "" rename-command KEYS "internal_KEYS"
-
慢查詢防御
- 設置超時閾值:
slowlog-log-slower-than 5000 # 5ms
- 定期分析:
SLOWLOG GET 50
- 設置超時閾值:
-
連接池配置
// Jedis 最佳配置示例 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(500); // 最大連接數 config.setMaxIdle(100); // 最大空閑連接 config.setMinIdle(20); // 最小空閑連接 config.setMaxWaitMillis(2000); // 最大等待時間
六、案例
以下通過 6個高頻場景的對比案例 說明 Redis 鍵值設計的核心規范,幫助直觀理解:
案例1:用戶信息存儲設計
? 錯誤做法
# 大JSON直接存儲String類型,無過期時間
SET user_10001 '{name:"John",age:30,address:"...20個字段...",lastLogin:...}'
問題:
- Key無業務含義,易沖突
- Value超10KB違反大Key規范
- 高頻讀取時需全量解析JSON
? 正確方案
# 模塊化Key命名 + Hash分字段存儲 + 過期時間
HMSET user:profile:10001 name "John" age 30 address "..." lastLogin 1717040000
EXPIRE user:profile:10001 2592000 # 30天過期
優化點:
- 鍵結構清晰:
業務模塊:數據維度:ID
- 高頻字段獨立存取,減少網絡傳輸
- 兜底過期避免數據堆積
案例2:電商購物車設計
? 錯誤做法
# 用List存儲所有商品ID(可能產生大Key)
LPUSH cart:10001 "sku_123:5" "sku_456:3" ...(5000+商品)
問題:
- 超出5000元素的大Key閾值
- 分頁查詢困難
? 正確方案
# Hash分片存儲 + 計數器
HMSET cart:10001:page1 sku_123 5 sku_456 3
HMSET cart:10001:page2 sku_789 2 ...
# 獲取商品數量(原子操作)
HINCRBY cart:10001:page1 sku_123 1
優化點:
- 分片控制單個Key元素數量
- 利用Hash字段的原子計數特性
案例3:秒殺庫存熱點Key
? 錯誤做法
# 集中式庫存計數器(產生熱點Key)
SET stock:sku_8888 1000
DECR stock:sku_8888 # 所有請求集中訪問此Key
問題:
- 單Key承受極高QPS
- 集群模式下無法分散壓力
? 正確方案
# 庫存分片設計
SET stock:sku_8888:shard1 200
SET stock:sku_8888:shard2 200
...
SET stock:sku_8888:shard5 200# 客戶端隨機選擇分片扣減
DECR stock:sku_8888:shard{random(1-5)}
優化點:
- 通過分片分散熱點
- 結合本地緩存減少Redis訪問
案例4:頁面訪問計數器
? 錯誤做法
# 非原子操作導致計數不準
count = redis.GET('page_view:home')
redis.SET('page_view:home', count+1)
問題:
- 并發場景下數據不一致
- 頻繁GET/SET產生大量請求
? 正確方案
# 使用INCR原子操作
INCR page_view:home# 按小時滾動存儲(避免單Key過大)
INCR page_view:home:2024052715
優化點:
- 原子操作保證準確性
- 時間分片控制Key規模
案例5:用戶消息通知列表
? 錯誤做法
# 用String存儲JSON數組(頻繁全量讀寫)
SET msg:10001 '[{id:1,content:"..."}, {...1000條數據}]'
問題:
- 大Value導致網絡阻塞
- 修改任意消息需全量更新
? 正確方案
# 使用ZSET按時間排序存儲
ZADD msg:10001 1717040000 '{"id":1,"content":"..."}'
ZADD msg:10001 1717040001 '{"id":2,"content":"..."}'# 分頁查詢最新消息
ZREVRANGE msg:10001 0 9 WITHSCORES
優化點:
- 天然支持按時間排序和分頁
- 單個消息的增刪不影響整體
案例6:社交關系存儲
? 錯誤做法
# 用String存儲用戶粉絲列表(大JSON數組)
SET followers:10001 "[20001,20002,...50000個用戶ID]"
問題:
- 50000個ID超過大Key限制
- 判斷是否關注需全量掃描
? 正確方案
# 使用Set存儲關系 + 分頁控制
SADD following:10001 20001 20002 ... # 最多5000元素/Key
SADD following:10001:page2 20003 ... # 分片存儲# 檢查關注關系
SISMEMBER following:10001 20001
優化點:
- 分片規避大Key
- 使用原生集合操作提升效率
總結技巧
- Key設計三要素:業務線明確(
user
)、數據類型清晰(profile
)、標識唯一(10001
) - Value選擇原則:
- 優先使用 Hash 替代 String 存儲對象
- 需要
排序用 ZSET
,去重用 Set
,隊列用 List
- 性能壓測公式:
# 模擬高并發場景 redis-benchmark -h 127.0.0.1 -p 6379 -n 100000 -c 100 -t set,get