3. 数据类型详解
Redis 的数据结构就像一个「百宝箱」,每种类型都是解决特定问题的利器。让我们一一认识它们。
3.1 String(字符串)—— 最基础的积木
🔑 比喻:String 就像一个抽屉,一个 Key 对应一个标签,Value 是抽屉里的东西。简单直接,万能百搭。
📌 场景:缓存、计数器、分布式锁、存储序列化对象
# 设置和获取
SET user:1:name "张三"
GET user:1:name"张三"# 计数器 —— 一篇文章的阅读量
SET article:1001:views 0
INCR article:1001:views
INCR article:1001:views
INCRBY article:1001:views 5
GET article:1001:views"7"# 设置过期时间(秒),自动过期
SET captcha:abc123 "8392" EX 300
TTL captcha:abc123(integer) 297# 分布式锁 —— NX 表示 key 不存在时才设置
SET lock:order:1001 "owner_001" NX EX 10OK3.2 List(列表)—— 消息队列的雏形
📋 比喻:List 就像一根传送带,从左边放进去(LPUSH),从右边取出来(RPOP),实现先进先出。
📌 场景:消息队列、最新消息列表、任务队列、时间线
# 模拟消息队列:生产者
LPUSH queue:email "user1@example.com|欢迎注册"
LPUSH queue:email "user2@example.com|密码重置"
# 查看队列长度
LLEN queue:email
# 消费者:从右边取出
RPOP queue:email(integer) 2
"user1@example.com|欢迎注册"# 阻塞弹出:如果没有消息,最多等 5 秒
BRPOP queue:email 5
# 获取列表区间(分页查看)
LPUSH timeline:uid1001 "推文A" "推文B" "推文C"
LRANGE timeline:uid1001 0 91) "推文C"
2) "推文B"
3) "推文A"3.3 Hash(哈希)—— 对象的完美容器
📦 比喻:Hash 就像一个档案袋,外面贴着标签(Key),里面装着多张卡片(Field-Value),每张卡片记录一条信息。
📌 场景:存储用户信息、商品详情、配置项
# 存储用户信息
HSET user:1001 name "李四" age 28 email "lisi@example.com" vip 1
# 获取单个字段
HGET user:1001 name
# 获取所有字段
HGETALL user:1001
# 判断字段是否存在
HEXISTS user:1001 phone
# 原子递增某个字段
HINCRBY user:1001 age 1"李四"
1) "name"
2) "李四"
3) "age"
4) "28"
5) "email"
6) "lisi@example.com"
7) "vip"
8) "1"
(integer) 0
(integer) 29💡 提示: 当 Hash 字段数少于 128 个且每个值小于 64 字节时,Redis 会用ziplist编码,内存占用极低!这是存储用户信息的最佳选择。
3.4 Set(集合)—— 不重复的标签盒
🏷️ 比喻:Set 就像一个装满弹珠的盒子,每个弹珠颜色不同(元素唯一),你可以快速判断某种颜色的弹珠是否在盒中。
📌 场景:标签系统、共同好友、去重、抽奖
# 给文章打标签
SADD article:1001:tags "Redis" "数据库" "缓存" "后端"
SADD article:1002:tags "Redis" "NoSQL" "性能"
# 获取所有标签
SMEMBERS article:1001:tags
# 交集:共同标签
SINTER article:1001:tags article:1002:tags
# 并集:所有标签
SUNION article:1001:tags article:1002:tags
# 差集:文章 1 有但文章 2 没有的标签
SDIFF article:1001:tags article:1002:tags
# 随机抽奖:抽 2 个中奖用户
SADD lottery:2024 "user1" "user2" "user3" "user4" "user5"
SRANDMEMBER lottery:2024 21) "Redis"
2) "数据库"
3) "缓存"
4) "后端"
1) "Redis"
1) "Redis"
2) "数据库"
3) "缓存"
4) "后端"
5) "NoSQL"
6) "性能"
1) "数据库"
2) "缓存"
3) "后端"
1) "user3"
2) "user1"3.5 Sorted Set(有序集合)—— 自动排序的排行榜
🏆 比喻:Sorted Set 就像一个实时更新的积分排行榜,每个参赛者都有一个分数,自动按分数排序。
📌 场景:排行榜、延迟队列、优先级任务、范围查询
# 游戏排行榜:ZADD key score member
ZADD leaderboard 1500 "玩家A"
ZADD leaderboard 2300 "玩家B"
ZADD leaderboard 1800 "玩家C"
ZADD leaderboard 3100 "玩家D"
ZADD leaderboard 900 "玩家E"
# 按分数从高到低排序(前 3 名)
ZREVRANGE leaderboard 0 2 WITHSCORES
# 查询某个玩家的排名(从 0 开始)
ZREVRANK leaderboard "玩家A"
# 给玩家加分
ZINCRBY leaderboard 500 "玩家A"
# 查询分数在 1000~3000 之间的玩家
ZRANGEBYSCORE leaderboard 1000 3000 WITHSCORES1) "玩家D"
2) "3100"
3) "玩家B"
4) "2300"
5) "玩家C"
6) "1800"
(integer) 3
"2000"
1) "玩家C"
2) "1800"
3) "玩家B"
4) "2300"
5) "玩家A"
6) "2000"
7) "玩家D"
8) "3100"3.6 Bitmap(位图)—— 超级省空间的开关面板
💡 比喻:Bitmap 就像一排灯泡开关,每个位置只有开/关两种状态。1 亿用户的签到状态只需 12MB 内存!
📌 场景:用户签到、在线状态、特征标记、布隆过滤器
# 用户 1001 在第 1 天签到
SETBIT sign:1001:202401 0 1
# 用户 1001 在第 5 天签到
SETBIT sign:1001:202401 4 1
# 用户 1001 在第 31 天签到
SETBIT sign:1001:202401 30 1
# 检查第 5 天是否签到
GETBIT sign:1001:202401 4
# 统计本月签到天数
BITCOUNT sign:1001:202401
# 检查第 3 天是否签到
GETBIT sign:1001:202401 2(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 3
(integer) 03.7 HyperLogLog —— 神奇的去重计数器
🔮 比喻:HyperLogLog 就像一个神奇的「估算大师」,它不需要记住每个元素,却能以极小的内存(固定 12KB)统计出近乎精确的去重数量。
📌 场景:UV(独立访客)统计、日活用户数、基数估算
# 统计网站 UV(独立访客数)
PFADD uv:20240101 "user_001" "user_002" "user_003"
PFADD uv:20240101 "user_004" "user_002" "user_005"
PFADD uv:20240101 "user_001" "user_006"
# 返回去重后的数量(误差约 0.81%)
PFCOUNT uv:20240101
# 合并多天的 UV 统计
PFADD uv:20240102 "user_007" "user_008" "user_002"
PFMERGE uv:202401_all uv:20240101 uv:20240102
PFCOUNT uv:202401_all(integer) 1
(integer) 1
(integer) 1
(integer) 6
OK
(integer) 8⚠️ 注意: HyperLogLog 是概率算法,统计结果是近似值(误差约 0.81%)。适合数据量巨大、允许微小误差的场景。如果需要精确计数,请用 Set。
3.8 Stream —— 新一代消息队列
📡 比喻:Stream 就像一个「带存档的广播电台」,新听众可以回听历史节目(消费者组),不怕错过任何消息。
📌 场景:消息队列、事件溯源、日志收集
# 生产者:添加消息到 Stream
XADD mystream * user "张三" action "login" ip "192.168.1.100"
XADD mystream * user "李四" action "purchase" amount "299"
XADD mystream * user "王五" action "logout""1704067200000-0"
"1704067200100-1"
"1704067200200-2"# 消费者:读取消息
XRANGE mystream - +
# 读取最新 2 条
XREVRANGE mystream + - COUNT 2
# 创建消费者组
XGROUP CREATE mystream mygroup $ MKSTREAM
# 消费者组消费(每条消息只分发给一个消费者)
XREADGROUP GROUP mygroup consumer1 COUNT 1 BLOCK 5000 STREAMS mystream >
# 确认消息已处理
XACK mystream mygroup 1704067200000-01) 1) "1704067200000-0"
2) 1) "user"
2) "张三"
3) "action"
4) "login"
5) "ip"
6) "192.168.1.100"
2) 1) "1704067200100-1"
2) 1) "user"
2) "李四"
3) "action"
4) "purchase"
5) "amount"
6) "299"
3) 1) "1704067200200-2"
2) 1) "user"
2) "王五"
3) "action"
4) "logout"
OK
1) 1) "mystream"
2) 1) 1) "1704067200100-1"
2) 1) "user"
2) "李四"
3) "action"
4) "purchase"
5) "amount"
6) "299"
(integer) 1数据类型选择速查
| 需求 | 推荐类型 | 示例 |
|---|---|---|
| 简单缓存 | String | 缓存用户 Token |
| 对象存储 | Hash | 用户个人信息 |
| 消息队列 | Stream / List | 订单处理队列 |
| 排行榜 | Sorted Set | 商品销量排行 |
| 去重集合 | Set | 文章标签 |
| 海量计数 | HyperLogLog | 网站 UV |
| 位操作 | Bitmap | 每日签到 |
| 时间序列 | Stream | 日志采集 |