[toc]
| 单词 | 词性 | 音标 | 含义 |
|---|---|---|---|
| rank | n./v. | /ræŋk/ | 排名(ZRANK 升序排名、ZREVRANK 降序排名) |
| score | n. | /skɔː(r)/ | 分数(ZSet 每个成员的权重,按它排序) |
| sorted | adj. | /ˈsɔːtɪd/ | 有序的(ZSet 元素按 score 从小到大排序) |
| geospatial | adj. | /ˌdʒiːəʊˈspeɪʃl/ | 地理空间的(Geo 类型存经纬度,按半径查附近) |
| hyperloglog | n. | /ˌhaɪpəˈlɒɡlɒɡlɒɡ/ | 基数统计(PFADD/PFCOUNT 估算不重复元素个数,内存极小) |
| bitmap | n. | /ˈbɪtmæp/ | 位图(SETBIT/GETBIT/BITCOUNT 对二进制位操作,签到用) |
| cardinality | n. | /ˌkɑːdɪˈnæləti/ | 基数(集合中不重复元素的个数) |
| stream | n. | /striːm/ | 流(Redis 5+ 的日志型消息队列,生产者/消费者组) |
Lecture05-Redis-数据类型-ZSet与高级类型
1、ZSet(有序集合)
1、什么是 ZSet
ZSet 和 Set 一样是去重的成员集合,但每个成员关联一个 score(分数,double),成员按 score 从小到大排序。
Key = "rank:game"
member(玩家) score(分数)
┌─────────────┐
│ jerry 87 ← 排名 0(最低)
│ harry 136
│ peter 155 ← 排名 2(最高)
└─────────────┘
- 成员唯一,score 可以重复。
- 底层:小数据用 ziplist,大数据用 跳表 skiplist + dict(查找快 + 范围查询 + 唯一性检查兼顾)。
2、常用命令
| 命令 | 功能 |
|---|---|
zadd key score member [score member...] | 添加成员及分数 |
zrange key 起始 结束 [WITHSCORES] | 升序返回索引区间(0 第一个,-1 最后一个) |
zrevrange key 起始 结束 [WITHSCORES] | 降序返回(排行榜第一名在前) |
zrangebyscore key min max [WITHSCORES] | 按分数区间升序返回 |
zrevrangebyscore key max min [WITHSCORES] | 按分数区间降序返回 |
zincrby key 增量 member | 给成员 score 加增量(排行榜实时加分) |
zrem key member | 删除成员 |
zcount key min max | 统计分数区间内成员个数 |
zrank key member | 升序排名(从 0 开始) |
zrevrank key member | 降序排名 |
zscore key member | 取成员分数 |
zpopmax/zpopmin key [n] | 弹出分数最高/最低的 n 个(延迟任务取最紧急) |
3、操作演示
# 添加 5 名玩家成绩
127.0.0.1:6379> zadd rank:game 55.5 gang 65.5 ming 75.5 qiang 85.5 jun 95.5 hong
(integer) 5
# 升序(分数从小到大)
127.0.0.1:6379> zrange rank:game 0 -1 withscores
1) "gang"
2) "55.5"
...
# 降序(排行榜第一名在前)
127.0.0.1:6379> zrevrange rank:game 0 -1 withscores
1) "hong"
2) "95.5"
...
# 分数区间查询:60~90 分的学生
127.0.0.1:6379> zrangebyscore rank:game 60 90 withscores
1) "ming"
2) "65.5"
...
# 实时加分
127.0.0.1:6379> zincrby rank:game 5 gang
"60.5"
# 排名
127.0.0.1:6379> zrank rank:game ming
(integer) 0
127.0.0.1:6379> zrevrank rank:game hong
(integer) 0
4、典型应用场景
| 场景 | 用法 |
|---|---|
| 排行榜 | 分数做 score,ZREVRANGE 0 -1 取前 N 名 |
| 延迟任务 / 定时队列 | 到期时间戳做 score,ZRANGEBYSCORE now +inf 取到期任务,ZPOPMIN 取最紧急 |
| 购物车 / 最新订单 | 时间戳做 score,按时间排序取列表 |
| 打赏 / 人气榜 | ZINCRBY 实时累加分数 |
| 限流 / 滑动窗口 | 时间戳做 member,ZREMRANGEBYSCORE 清理窗口外数据 |
2、Geo(地理位置,了解)
Redis 3.2+ 提供,底层用 ZSet 实现(score 存经纬度编码),用于"附近的人/门店"。
| 命令 | 功能 |
|---|---|
geoadd key 经度 纬度 成员 | 添加位置 |
geopos key 成员 | 获取成员经纬度 |
geodist key a b [km] | 计算两地直线距离 |
georadius key 经 纬 半径 km | 以给定坐标为中心,半径内查成员 |
georadiusbymember key 成员 半径 km | 以某个成员为中心,半径内查其他成员 |
127.0.0.1:6379> geoadd city:pos 114.085947 22.547 shenzhen
(integer) 1
127.0.0.1:6379> geoadd city:pos 113.280637 23.125178 guangzhou
(integer) 1
127.0.0.1:6379> geodist city:pos shenzhen guangzhou km
"104.6426"
127.0.0.1:6379> georadius city:pos 114 22 100 km
1) "shenzhen"
经纬度可通过
http://www.jsons.cn/lngcode这类网站查询。注意有效经度 -180~180、纬度 -85.05~85.05。
3、HyperLogLog(基数统计)
用于大数据量去重计数(如统计 UV:一个用户一天访问多次只算一次)。每个键约 12KB 内存,可估算近 2^64 个不同元素。
| 命令 | 功能 |
|---|---|
pfadd key 元素... | 添加元素(去重) |
pfcount key [key...] | 统计不重复元素个数 |
pfmerge dest s1 s2 | 合并多个统计到 dest |
127.0.0.1:6379> pfadd uv:2026-09-28 userA userB userC userA userB
(integer) 1
127.0.0.1:6379> pfcount uv:2026-09-28
(integer) 3 # 重复的 userA/userB 只算一次
特点:省内存、快、结果有极小误差(约 0.81%)。适合"只要数量级、不要精确"的场景,如 UV、独立访客数。
4、Bitmap(位图)
对 String 的二进制位操作,每个位 0/1。适合大量布尔标记(签到、在线状态),极致省内存(1 亿用户每天 1 位 ≈ 12MB)。
| 命令 | 功能 |
|---|---|
setbit key 位 0/1 | 设置某一位 |
getbit key 位 | 读取某一位 |
bitcount key | 统计所有为 1 的位数量 |
# 签到:位 0 表示第 1 天
127.0.0.1:6379> setbit sign:user:1001 0 1
(integer) 0
127.0.0.1:6379> setbit sign:user:1001 1 1
(integer) 0
127.0.0.1:6379> getbit sign:user:1001 1
(integer) 1
127.0.0.1:6379> bitcount sign:user:1001
(integer) 2 # 连续签到 2 天
经典用法:连续签到天数、在线状态、布隆过滤器(与 L7 缓存穿透有关)。
5、Stream(流式消息队列,了解)
Redis 5+ 提供日志型消息队列,支持多消费者、消费者组、消息确认,比 List 队列功能更完整,可作为轻量消息中间件(正式消息中间件见后续 RabbitMQ 课程)。
# 生产者
127.0.0.1:6379> xadd order:stream * order_id 1001 amount 99
"1727400000000-0"
# 消费者组读取(略)
本课程只做了解:真正做消息队列,项目里更多用 RabbitMQ / Kafka。Redis Stream 适合"顺便用一下、不想引入额外中间件"的简单场景。
6、数据类型总结
| 类型 | 特点 | 典型场景 |
|---|---|---|
| string | 二进制安全、原子计数 | 验证码、Token、计数器 |
| hash | 对象字段级读写 | 用户信息、购物车 |
| list | 有序可重复,头尾快 | 队列、栈、最新列表 |
| set | 去重、集合运算 | 关注、去重、抽奖、标签 |
| zset | 有序去重,按分数排 | 排行榜、延迟任务 |
| geo | 经纬度、半径查询 | 附近的人/门店 |
| hyperloglog | 基数统计、省内存 | UV、独立访客 |
| bitmap | 位操作、极省内存 | 签到、在线状态、布隆 |
| stream | 日志型消息队列 | 简单异步消息、日志 |
7、课堂练习
- 用 ZSet 做一个"本周热销榜":
ZADD5 个商品及销量,用ZREVRANGE 0 2取前三名,再用ZINCRBY给一个商品加分看排名变化。 - 用 HyperLogLog 统计"今日 UV":
PFADD若干用户(含重复),PFCOUNT看结果。 - 用 Bitmap 做"连续签到 7 天":
SETBIT前 7 位为 1,BITCOUNT得到 7。 - (了解)用
GEOADD/GEODIST记录两个城市并计算距离。
8、本节验证
- 会用 ZADD/ZRANGE/ZREVRANGE/ZRANK/ZSCORE 实现排行榜与按分数查询 ✅
- 会用 ZINCRBY 实时加分、按分数区间查询 ✅
- 了解 Geo 附近查询、HyperLogLog 基数统计、Bitmap 位图签到 ✅
- 了解 Stream 流式消息队列,能根据场景选对数据类型 ✅