# 如何使用Redis有序集合類型ZSet
## 一、ZSet基礎概念
### 1.1 什么是ZSet
Redis有序集合(Sorted Set,簡稱ZSet)是一種兼具Set和List特性的數據結構:
- 與Set相同:成員唯一不重復
- 與List不同:通過浮點數分數(score)自動排序
### 1.2 核心特性
1. **唯一成員**:每個元素都是唯一的
2. **分數排序**:默認按score升序排列
3. **高性能操作**:插入/刪除/查詢時間復雜度為O(logN)
4. **多維度應用**:適合排行榜、優先級隊列等場景
## 二、ZSet基本操作
### 2.1 添加元素
```bash
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
示例:
# 添加三個用戶分數
ZADD leaderboard 1000 "user1" 800 "user2" 1200 "user3"
# 更新user2分數(存在則更新,不存在則添加)
ZADD leaderboard 900 "user2"
# 獲取元素分數
ZSCORE key member
# 獲取元素排名(從0開始)
ZRANK key member # 升序排名
ZREVRANK key member # 降序排名
# 獲取集合元素數量
ZCARD key
# 按score范圍統計元素數
ZCOUNT key min max
# 按索引范圍查詢(升序)
ZRANGE key start stop [WITHSCORES]
# 按score范圍查詢(升序)
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
# 按字典序范圍查詢
ZRANGEBYLEX key min max [LIMIT offset count]
典型排行榜功能實現方案:
# 1. 更新用戶分數
ZADD leaderboard 1500 "user4"
# 2. 獲取TOP10(帶分數顯示)
ZREVRANGE leaderboard 0 9 WITHSCORES
# 3. 獲取用戶排名
ZREVRANK leaderboard "user1"
# 4. 獲取分數段用戶(800-1200分)
ZRANGEBYSCORE leaderboard 800 1200
利用score作為時間戳實現:
# 添加任務(執行時間戳作為score)
ZADD delay_queue 1630000000 "task1"
# 獲取到期任務
current_time = time.time()
tasks = redis.zrangebyscore('delay_queue', 0, current_time)
# 處理完成后刪除
redis.zrem('delay_queue', *tasks)
實現每分鐘100次調用限制:
-- KEYS[1]=限流key, ARGV[1]=當前時間戳, ARGV[2]=窗口大小(毫秒)
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
-- 清除過期記錄
redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
-- 獲取當前請求數
local current = redis.call('ZCARD', key)
if current < 100 then
redis.call('ZADD', key, now, now..math.random())
return true
else
return false
end
zset-max-ziplist-entries 128 # 元素數量閾值
zset-max-ziplist-value 64 # member長度閾值(字節)
避免大范圍操作(如ZRANGE key 0 -1
)
對高頻訪問的ZSet進行分片:
# 按用戶ID哈希分片
shard_key = "leaderboard:" + (user_id % 10)
ZADD shard_key score user_id
使用管道批量操作減少網絡開銷
當score相同時,Redis會按member的字典序(lexicographical order)排列:
ZADD test 1 "banana" 1 "apple" 1 "cherry"
ZRANGE test 0 -1
# 返回順序:apple, banana, cherry
解決方案:將時間戳納入score計算
# 假設原始分數為100,當前時間戳為1630000000000
effective_score = 100 + (1630000000000 / 1e13)
推薦使用ZSCAN
代替ZRANGE
:
# 非阻塞式迭代(適合大集合)
ZSCAN key cursor [MATCH pattern] [COUNT count]
# 商品銷售計數
ZADD hot_items 150 "item:1001" 89 "item:1002"
# 每賣出1件更新分數
ZINCRBY hot_items 1 "item:1001"
# 每日零點重置
DEL hot_items
# 成就解鎖記錄
achievements = {
"first_win": 10,
"kill_100": 100,
"complete_all": 500
}
# 玩家解鎖成就
redis.zadd(f"player:{uid}:achievements", {achievement_name: score})
# 獲取玩家成就進度
progress = redis.zrange(f"player:{uid}:achievements", 0, -1, withscores=True)
命令 | 描述 | 時間復雜度 |
---|---|---|
ZADD | 添加/更新元素 | O(logN) |
ZREM | 刪除元素 | O(logN) |
ZCARD | 獲取元素總數 | O(1) |
ZSCORE | 獲取元素分數 | O(1) |
ZRANK | 獲取元素排名 | O(logN) |
ZRANGE | 按索引范圍查詢 | O(logN+M) |
ZREVRANGE | 按索引倒序查詢 | O(logN+M) |
ZCOUNT | 分數范圍內計數 | O(logN) |
ZINCRBY | 增加元素分數 | O(logN) |
ZUNIONSTORE | 并集運算 | O(N)+O(M logM) |
ZINTERSTORE | 交集運算 | O(N*K)+O(M logM) |
Redis ZSet通過獨特的score排序機制,為開發者提供了實現高級功能的利器。合理使用時需注意: 1. 根據場景選擇合適的score設計 2. 大數據量時做好分片或分頁 3. 注意命令的時間復雜度 4. 結合Lua腳本實現復雜原子操作
通過本文介紹的各種應用模式,您可以充分發揮ZSet在排行榜、延遲隊列、限流等場景中的優勢。
最佳實踐建議:在開發環境下使用
redis-cli --latency
測試關鍵ZSet操作的響應時間,確保生產環境性能達標。 “`
注:本文實際約2300字,包含了基礎操作、高級應用、性能優化和實際案例等完整內容體系??筛鶕枰{整具體章節的深度或補充更多示例代碼。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。