1. Redis 簡介與核心特性
Redis(Remote Dictionary Server)是一款開源的內存數據存儲系統,支持多種數據結構,兼具高性能、持久化、分布式等特性,廣泛用于緩存、數據庫、消息中間件等場景。其核心特性包括:
- 高性能:基于內存操作,單線程模型避免上下文切換開銷,QPS 可達 10 萬 +(取決于數據大小和命令復雜度);
- 多數據結構支持:不僅支持基礎的鍵值對,還提供 String、Hash、List 等豐富數據類型;
- 持久化:通過 RDB 和 AOF 機制將內存數據持久化到磁盤,防止數據丟失;
- 高可用:支持主從復制、哨兵(Sentinel)實現故障自動轉移;
- 分布式:Redis Cluster 提供分片存儲,突破單機內存限制;
- 功能豐富:支持事務、發布訂閱、Lua 腳本、地理空間等高級特性。
2. 核心數據類型及應用場景詳解
Redis 提供8 種核心數據類型,每種類型針對特定場景優化,以下為詳細說明:
2.1 String(字符串)
數據結構特點
- 二進制安全:可存儲文本、圖片、序列化對象等任意二進制數據;
- 最大容量:單個 String 值最大 512MB;
- 底層實現:小字符串(<39 字節)用 SDS(簡單動態字符串),大字符串用 embstr/raw 編碼。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
SET key value [EX seconds] | 設置鍵值對,可選過期時間 | SET user:1001 '{"name":"Alice","age":25}' EX 3600 (緩存 1 小時) |
GET key | 獲取鍵值 | GET user:1001 → 返回用戶信息 JSON |
INCR key | 整數自增 1(原子操作) | INCR article:read:10086 (文章閱讀量 + 1) |
DECR key | 整數自減 1(原子操作) | DECR stock:iphone15 (庫存 - 1) |
APPEND key value | 追加字符串到值末尾 | APPEND log:user:1001 " login success" |
應用場景
緩存熱點數據:存儲用戶信息、商品詳情等高頻訪問數據,減輕數據庫壓力。
示例:電商場景中,緩存商品詳情頁數據:SET product:10001 '{"id":10001,"name":"無線耳機","price":999}' EX 1800
(緩存 30 分鐘),用戶訪問時直接從 Redis 獲取,無需查詢 MySQL。計數器:利用
INCR
/DECR
的原子性,實現文章閱讀量、視頻播放量、接口請求次數統計。
示例:短視頻平臺統計視頻播放量:用戶每次觀看視頻時,執行INCR video:play:9527
,后臺定期將計數器值同步到數據庫。分布式鎖:基于
SET key value NX EX
命令(NX:不存在才設置,EX:過期時間)實現分布式鎖,防止并發操作沖突。
示例:秒殺場景中,通過SET lock:seckill:1001 "1" NX EX 10
搶占鎖,獲取鎖后執行庫存扣減,執行完畢釋放鎖(DEL lock:seckill:1001
)。
2.2 Hash(哈希)
數據結構特點
- 鍵值對集合:一個 Hash 鍵包含多個
field-value
鍵值對,類似 JSON 對象; - 空間高效:適合存儲對象,可單獨操作字段(無需整體更新);
- 底層實現:小 Hash(field 數量少且值小)用壓縮列表,大 Hash 用哈希表。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
HSET key field value | 設置 Hash 字段值 | HSET user:1001 name "Alice" age 25 email "alice@example.com" |
HGET key field | 獲取 Hash 字段值 | HGET user:1001 name → "Alice" |
HMGET key field1 field2 | 批量獲取 Hash 字段值 | HMGET user:1001 name age → ["Alice", "25"] |
HGETALL key | 獲取 Hash 所有字段和值 | HGETALL user:1001 → ["name","Alice","age","25",...] |
HINCRBY key field num | 字段值整數自增 num(原子操作) | HINCRBY user:1001 score 10 (用戶積分 + 10) |
應用場景
對象存儲:存儲用戶、商品等結構化數據,支持字段級更新,比 String 更靈活。
示例:社交平臺存儲用戶資料:HSET user:1001 name "Bob" avatar "avatar.jpg" vip_level 3
,更新頭像時僅需HSET user:1001 avatar "new_avatar.jpg"
,無需修改整個對象。購物車:以用戶 ID 為 Hash 鍵,商品 ID 為 field,數量為 value,實現購物車增刪改查。
示例:用戶 1001 的購物車:HSET cart:1001 2001 2 2002 1
(商品 2001 數量 2,商品 2002 數量 1),修改數量時HSET cart:1001 2001 3
,清空購物車時DEL cart:1001
。
2.3 List(列表)
數據結構特點
- 有序字符串列表:元素按插入順序排列,支持兩端插入 / 刪除;
- 雙向鏈表特性:可充當棧(LIFO)或隊列(FIFO);
- 底層實現:小 List(元素少且小)用壓縮列表,大 List 用雙向鏈表。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
LPUSH key value1 [value2] | 從列表左側插入元素 | LPUSH msg:queue "msg1" "msg2" (左側插入兩條消息) |
RPUSH key value1 [value2] | 從列表右側插入元素 | RPUSH article:latest 1001 1002 (右側追加文章 ID) |
LPOP key | 從列表左側彈出元素(返回并刪除) | LPOP msg:queue → "msg2"(棧模式:后進先出) |
RPOP key | 從列表右側彈出元素(返回并刪除) | RPOP msg:queue → "msg1"(隊列模式:先進先出) |
LRANGE key start stop | 獲取列表指定范圍元素(0 為頭,-1 為尾) | LRANGE article:latest 0 9 → 獲取最新 10 篇文章 ID |
應用場景
消息隊列:基于
LPUSH+RPOP
實現簡單的 FIFO 消息隊列,生產者左側插入消息,消費者右側彈出消息。
示例:訂單系統異步通知:訂單創建后,LPUSH order:notify "order123"
,通知服務循環執行RPOP order:notify
獲取訂單 ID 并發送短信。最新數據展示:基于
LPUSH+LRANGE
實現 “最新 N 條數據” 功能,如最新文章、最近評論。
示例:博客平臺展示最新 5 篇文章:發布文章時LPUSH article:latest 3001
(文章 ID),前端調用LRANGE article:latest 0 4
獲取前 5 篇文章 ID,再查詢詳情。
2.4 Set(集合)
數據結構特點
- 無序字符串集合:元素唯一(自動去重),不保證順序;
- 支持集合運算:交集、并集、差集,時間復雜度 O (N);
- 底層實現:小 Set 用整數集合(元素為整數且少),大 Set 用哈希表。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
SADD key member1 member2 | 向集合添加元素(自動去重) | SADD user:tags:1001 "tech" "music" "sports" (用戶 1001 的標簽) |
SMEMBERS key | 獲取集合所有元素 | SMEMBERS user:tags:1001 → ["tech","music","sports"] |
SISMEMBER key member | 判斷元素是否在集合中 | SISMEMBER user:tags:1001 "music" → 1(存在) |
SINTER key1 key2 | 計算兩個集合的交集 | SINTER user:friends:1001 user:friends:1002 (共同好友) |
SUNION key1 key2 | 計算兩個集合的并集 | SUNION user:tags:1001 user:tags:1002 (合并標簽) |
SREM key member | 從集合刪除元素 | SREM user:tags:1001 "sports" (移除標簽) |
應用場景
標簽系統:存儲用戶興趣標簽、文章分類等,支持標簽添加、刪除、查詢。
示例:內容平臺用戶標簽管理:用戶 1001 添加 “科技”“音樂” 標簽后,可通過SMEMBERS user:tags:1001
獲取所有標簽,推薦內容時根據標簽匹配。共同好友 / 興趣:通過
SINTER
計算交集,實現社交平臺 “共同好友” 功能。
示例:用戶 A(ID1001)和用戶 B(ID1002)的好友列表分別為user:friends:1001
和user:friends:1002
,執行SINTER user:friends:1001 user:friends:1002
即可獲取兩人的共同好友 ID。去重統計:利用集合元素唯一性,統計 UV(獨立訪客)、去重 ID 列表等。
示例:統計某活動參與用戶 ID(去重):SADD activity:100:users 5001 5002 5001
(自動去重后僅保留 5001、5002),SCARD activity:100:users
→ 2(參與人數)。
2.5 Sorted Set(ZSet,有序集合)
數據結構特點
- 有序唯一元素:每個元素關聯一個
score
(浮點數),按score
升序排列,元素不可重復; - 高效排序與查詢:支持按
score
范圍、排名范圍查詢,底層基于 “跳躍表” 實現,時間復雜度 O (logN); - 支持
score
動態更新:修改元素score
后自動調整排序位置。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
ZADD key score member | 添加元素及 score | ZADD game:rank 95 "userA" 88 "userB" 92 "userC" (游戲排行榜) |
ZRANGE key start stop [WITHSCORES] | 按 score 升序獲取排名范圍內元素(0 為第一名) | ZRANGE game:rank 0 2 WITHSCORES → ["userB",88,"userC",92,"userA",95] |
ZREVRANGE key start stop [WITHSCORES] | 按 score 降序獲取排名范圍內元素 | ZREVRANGE game:rank 0 2 WITHSCORES → ["userA",95,"userC",92,"userB",88](前三名) |
ZSCORE key member | 獲取元素 score | ZSCORE game:rank "userA" → 95 |
ZINCRBY key increment member | 元素 score 自增 increment(原子操作) | ZINCRBY game:rank 5 "userB" (userB 分數 + 5 → 93) |
ZRANK key member | 獲取元素升序排名(0 為第一名) | ZRANK game:rank "userB" → 0(score 88 時排名第一) |
應用場景
排行榜系統:實時展示用戶積分、商品銷量、視頻播放量等排名。
示例:直播平臺禮物榜:觀眾送禮物時,ZINCRBY gift:rank:room100 50 "user888"
(用戶 888 積分 + 50),前端調用ZREVRANGE gift:rank:room100 0 9 WITHSCORES
展示 “房間貢獻榜 TOP10”。帶權重的消息隊列:按
score
(權重)優先級消費消息,高權重消息優先處理。
示例:訂單處理系統:普通訂單ZADD order:queue 1 "order1001"
,VIP 訂單ZADD order:queue 10 "order1002"
,消費者通過ZREVRANGE order:queue 0 0
優先獲取 VIP 訂單處理。范圍統計:按
score
范圍篩選元素,如 “積分> 1000 的用戶”“考試分數 80-90 分的學生”。
示例:教育平臺統計成績:ZRANGEBYSCORE exam:math 80 90
→ 獲取數學成績 80-90 分的學生 ID。
3. 高級數據類型
3.1 Bitmap(位圖)
數據結構特點
- 位級操作:將字符串視為 “位數組”,每個位(bit)表示一個二值狀態(0/1);
- 空間高效:1 字節 = 8 位,存儲 100 萬個狀態僅需約 125KB;
- 支持位運算:與(AND)、或(OR)、異或(XOR)、非(NOT)及位計數。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
SETBIT key offset value | 設置指定偏移量的位值(0/1) | SETBIT sign:user:1001 5 1 (用戶 1001 第 5 天簽到,偏移量從 0 開始) |
GETBIT key offset | 獲取指定偏移量的位值 | GETBIT sign:user:1001 5 → 1(第 5 天已簽到) |
BITCOUNT key [start end] | 統計位值為 1 的數量(可指定字節范圍) | BITCOUNT sign:user:1001 → 15(本月累計簽到 15 天) |
BITOP op destkey key1 [key2] | 對多個 Bitmap 執行位運算,結果存到 destkey | BITOP AND sign:both:1001_1002 sign:user:1001 sign:user:1002 (兩人共同簽到的天數) |
應用場景
簽到統計:記錄用戶每日簽到狀態,統計每月簽到天數、連續簽到天數。
示例:用戶 1001 的 2025 年 8 月簽到:SETBIT sign:user:1001:202508 0 1
(8 月 1 日簽到,偏移量 0)、SETBIT ... 2 1
(8 月 3 日簽到),BITCOUNT sign:user:1001:202508
→ 2(當月簽到 2 天)。用戶在線狀態:用位偏移量表示用戶 ID,位值 1 表示在線,0 表示離線,高效統計在線人數。
示例:平臺在線用戶:用戶 5001 在線 →SETBIT online:20250814 5001 1
,BITCOUNT online:20250814
→ 1000(當前在線人數)。
3.2 HyperLogLog(基數統計)
數據結構特點
- 基數估算:用于統計 “集合中不重復元素的個數”(基數),而非存儲元素本身;
- 空間極致優化:無論基數多大,單個 HyperLogLog 鍵僅占用約 12KB 內存;
- 概率性算法:存在 0.81% 的誤差(可接受范圍內),適合海量數據基數統計。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
PFADD key element1 [element2] | 添加元素到 HyperLogLog | PFADD uv:20250814 1001 1002 1001 1003 (網站當日 UV 統計) |
PFCOUNT key | 估算基數(不重復元素個數) | PFCOUNT uv:20250814 → 3(去重后 1001、1002、1003) |
PFMERGE destkey key1 [key2] | 合并多個 HyperLogLog 到 destkey | PFMERGE uv:202508 uv:20250801 uv:20250802 ... (合并 8 月每日 UV,統計月 UV) |
應用場景
UV 統計:統計網站 / 頁面的獨立訪客數,無需存儲用戶 ID,節省內存。
示例:電商首頁 UV:用戶訪問時PFADD uv:home:20250814 <user_id>
,當日結束后PFCOUNT uv:home:20250814
→ 50000(首頁當日 UV)。搜索關鍵詞去重:統計用戶搜索過的不重復關鍵詞數量,優化搜索推薦。
示例:PFADD search:keywords "phone" "book" "phone" "shoes"
,PFCOUNT search:keywords
→ 3(不重復關鍵詞數)。
3.3 Geospatial(地理空間)
數據結構特點
- 地理位置存儲:存儲經緯度坐標(經度范圍 - 180~180,緯度范圍 - 85.05112878~85.05112878),支持距離計算、范圍查詢;
- 底層基于 ZSet 實現:將經緯度編碼為
score
(Geohash 算法),通過 ZSet 命令間接操作。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
GEOADD key longitude latitude member | 添加地理位置 | GEOADD shops 116.403 39.914 "storeA" 116.410 39.905 "storeB" (北京商店坐標) |
GEODIST key member1 member2 [unit] | 計算兩個位置的距離(unit:m/km/mi/ft) | GEODIST shops storeA storeB km → 1.2(storeA 與 storeB 相距 1.2 公里) |
GEORADIUS key longitude latitude radius unit [WITHDIST] | 搜索指定坐標半徑內的位置 | GEORADIUS shops 116.4 39.9 5 km WITHDIST → 獲取天安門 5 公里內的商店及距離 |
應用場景
附近的人 / 地點:基于用戶當前坐標,搜索周邊一定范圍內的人或商家。
示例:外賣平臺 “附近商家”:用戶坐標(116.4, 39.9),GEORADIUS shops 116.4 39.9 3 km WITHDIST
→ 返回 3 公里內的商家及距離,按距離排序展示。地理位置圍欄:監控設備是否進入 / 離開指定區域(如物流包裹是否到達配送范圍)。
示例:物流場景中,GEORADIUS warehouse:1 120.0 30.0 10 km
→ 檢查 10 公里內是否有包裹(通過包裹 ID 關聯的坐標),觸發配送通知。
3.4 Stream(消息流)
數據結構特點
- 持久化消息隊列:支持消息持久化、消費確認、消費組(Consumer Group),解決 List 作為隊列時的消息丟失、重復消費問題;
- 消息 ID 自增:每條消息有唯一 ID(格式
timestamp-sequence
,如1723600000000-0
),保證有序性; - 消費組機制:支持多消費者協同消費,每個消費者處理不同消息,避免重復消費。
常用命令
命令 | 功能描述 | 示例 |
---|---|---|
XADD key * field value [field value] | 添加消息(* 表示自動生成 ID) | XADD orderStream * type "pay" orderId "123" amount 99 (訂單支付消息) |
XREAD COUNT count STREAMS key startId | 讀取消息(startId=0-0 表示從頭讀) | XREAD COUNT 1 STREAMS orderStream 0-0 → 讀取 1 條消息 |
XGROUP CREATE key groupName startId | 創建消費組 | XGROUP CREATE orderStream group1 $ ($ 表示從最新消息開始消費) |
XREADGROUP GROUP groupName consumer COUNT count STREAMS key > | 消費組內消費者讀取消息(> 表示未消費消息) | XREADGROUP GROUP group1 consumer1 COUNT 1 STREAMS orderStream > → consumer1 讀取 1 條未消費消息 |
XACK key groupName msgId | 確認消息已消費 | XACK orderStream group1 1723600000000-0 (確認消息處理完成) |
應用場景
- 可靠消息隊列:替代 List 實現高可靠消息傳遞,支持消息重試、消費確認,適合訂單處理、日志收集等場景。
示例:電商訂單系統:訂單支付后XADD payStream * orderId "123" status "success"
,下游物流服務通過消費組XREADGROUP
讀取消息并處理,處理完成后XACK
確認,避免消息丟失。
4. 持久化機制(RDB vs AOF)
Redis 支持兩種持久化方式,可單獨啟用或混合使用,核心目標是防止內存數據丟失。
4.1 RDB(Redis Database)
- 原理:在指定時間間隔內生成內存數據的快照文件(.rdb),保存到磁盤。
- 觸發方式:
- 手動觸發:
SAVE
(阻塞 Redis,適合離線備份)、BGSAVE
(fork 子進程執行,不阻塞主進程); - 自動觸發:配置文件中
save <seconds> <changes>
(如save 3600 1
:3600 秒內有 1 次修改則觸發)。
- 手動觸發:
- 優缺點:
- 優點:文件體積小,恢復速度快(直接加載快照到內存);
- 缺點:數據安全性低,兩次快照間的修改可能丟失(如 5 分鐘快照間隔,崩潰時丟失 5 分鐘數據)。
4.2 AOF(Append Only File)
- 原理:記錄所有寫命令(如 SET、HSET)到日志文件(.aof),重啟時通過重新執行命令恢復數據。
- 配置參數:
appendfsync always
:每條命令立即刷盤(安全性最高,性能最差);appendfsync everysec
:每秒刷盤一次(默認,平衡安全與性能,最多丟失 1 秒數據);appendfsync no
:由操作系統決定刷盤時機(性能最好,安全性最低)。
- AOF 重寫:解決 AOF 文件膨脹問題,通過
BGREWRITEAOF
命令生成新 AOF 文件(合并重復命令,如多次 INCR 合并為最終值)。 - 優缺點:
- 優點:數據安全性高,丟失數據少;
- 缺點:文件體積大,恢復速度慢(需重新執行所有命令)。
4.3 混合持久化(Redis 4.0+)
- 原理:AOF 文件頭部存儲 RDB 快照,尾部存儲增量 AOF 命令,結合 RDB 恢復快和 AOF 數據全的優點。
- 配置:
aof-use-rdb-preamble yes
(默認開啟)。
4.4 持久化方案選擇
場景 | 推薦方案 | 理由 |
---|---|---|
數據安全性要求高(如金融交易) | AOF(everysec)+ 混合持久化 | 最多丟失 1 秒數據,恢復速度較純 AOF 快 |
性能優先(如緩存場景) | RDB(或禁用持久化) | 減少磁盤 IO 開銷,緩存數據可從數據庫重建 |
災備需求 | RDB 定期備份 + AOF 實時記錄 | RDB 用于全量恢復,AOF 用于增量數據補充 |
5. 高可用方案(主從復制與哨兵)
5.1 主從復制
- 作用:實現數據備份與讀寫分離,主庫(Master)負責寫操作,從庫(Slave)同步主庫數據并提供讀服務。
- 原理:
- 全量復制:從庫首次連接主庫時,主庫生成 RDB 快照發送給從庫,從庫加載快照后,主庫再發送緩沖的增量命令;
- 增量復制:后續主庫將寫命令記錄到
repl_backlog_buffer
,從庫通過偏移量(offset)同步增量命令。
- 配置:從庫配置
slaveof <master-ip> <master-port>
,主庫無需額外配置。 - 應用:讀寫分離(主庫寫、從庫讀),如電商商品詳情查詢走從庫,減輕主庫壓力。
5.2 哨兵(Sentinel)
- 作用:監控主從節點狀態,實現自動故障轉移(主庫掛了后從庫自動升級為主庫)。
- 核心功能:
- 監控:定期檢查主從節點是否存活;
- 通知:通過 API 向管理員或其他應用發送故障通知;
- 自動故障轉移:主庫故障時,選舉從庫升級為主庫,其他從庫重新指向新主庫。
- 部署:通常部署 3 個哨兵節點(奇數,避免腦裂),配置文件指定監控的主庫信息。
- 示例:一主二從 + 三哨兵架構,主庫掛了后,哨兵通過投票選舉其中一個從庫升級為主庫,客戶端通過哨兵獲取新主庫地址繼續訪問。
6. Redis Cluster(分布式集群)
6.1 核心概念
- 分片存儲:將數據按 “槽位”(共 16384 個槽)分配到多個節點,每個節點負責一部分槽位(如 3 主節點各負責 5461 個槽);
- 主從復制:每個主節點可配置從節點,實現數據備份與故障轉移;
- 去中心化:無中心節點,客戶端直接與槽位對應節點通信,節點間通過 Gossip 協議交換狀態。
6.2 數據路由
- 槽位計算:客戶端根據
CRC16(key) % 16384
計算 key 所屬槽位; - 重定向:若客戶端連接的節點不負責目標槽位,返回
MOVED
錯誤,指引客戶端連接正確節點。
6.3 應用場景
- 海量數據存儲:突破單機內存限制,如存儲 100GB 數據,可通過 3 主 3 從集群(每主節點 30GB + 內存)分片存儲;
- 高并發訪問:多節點分擔讀寫壓力,提升整體吞吐量。
7. 性能優化實踐
7.1 鍵設計規范
- 命名規范:用冒號分隔命名空間,如
user:1001:info
、order:202508:list
,避免鍵名混亂; - 避免大鍵:單個 key 存儲數據不超過 10KB(如大 List、大 Hash 拆分存儲),防止操作阻塞 Redis;
- 過期鍵清理:對緩存數據設置合理過期時間(
EX
/PX
),避免內存溢出。
7.2 內存淘汰策略
當內存達到maxmemory
限制時,Redis 通過以下策略淘汰鍵(配置maxmemory-policy
)
策略名稱 | 說明(優先級從高到低) |
---|---|
volatile-lru | 從設置過期時間的鍵中,淘汰最近最少使用的鍵 |
allkeys-lru | 從所有鍵中,淘汰最近最少使用的鍵 |
volatile-ttl | 從設置過期時間的鍵中,淘汰剩余時間最短的鍵 |
noeviction | 不淘汰鍵,寫操作返回錯誤(默認,不推薦生產環境) |
推薦配置:緩存場景用allkeys-lru
(優先淘汰冷數據),業務數據用volatile-lru
(僅淘汰過期緩存)。
7.3 命令與網絡優化
- 批量操作:用
MSET
/MGET
(String)、HMSET
/HMGET
(Hash)替代循環單條命令,減少網絡往返; - Pipeline:客戶端將多個命令打包發送,Redis 批量執行后返回結果,適合大量小命令場景(如批量更新庫存);
- 避免阻塞命令:禁用
KEYS *
(遍歷所有鍵,阻塞 Redis),改用SCAN
(迭代遍歷);避免HGETALL
(大 Hash 全量獲取),改用HMGET
指定字段。
8. 總結
Redis 憑借豐富的數據結構、高性能、持久化、分布式支持等特性,成為緩存、數據庫、消息隊列等場景的首選工具。核心知識點包括:
- 數據類型:String(緩存、計數器)、Hash(對象存儲)、List(隊列)、Set(集合運算)、ZSet(排行榜)等,需結合場景選擇合適類型;
- 持久化:RDB(性能優先)與 AOF(安全優先),生產環境推薦混合持久化;
- 高可用:主從復制(讀寫分離)+ 哨兵(故障轉移);
- 分布式:Redis Cluster 實現分片存儲,突破單機限制。
通過合理設計鍵結構、優化命令、配置持久化與高可用策略,可充分發揮 Redis 性能,支撐高并發業務場景。