本文是大数据系列第 41 篇,介绍 Redis 三种高级数据类型:Bitmap 位图、Geo 地理位置与 Stream 消息流。
Bitmap 位图
核心概念:位图是一种用二进制位表示数据的数据结构,每个 bit 只能为 0 或 1,用来表示某个元素的值或状态。
空间效率
Bitmap 的最大优势在于极高的空间利用率。存储 10,000 个用户的签到状态:
- 传统方式(布尔值存 Set):约 40KB
- Bitmap 方式:约 1.25KB(节省超过 97%)
常用场景
- 用户签到打卡
- 在线用户统计
- 布隆过滤器
- 权限管理
- 去重计数
核心命令
| 命令 | 说明 |
|---|---|
SETBIT key offset value | 设置指定偏移量的 bit 值(0 或 1) |
GETBIT key offset | 获取指定偏移量的 bit 值 |
BITCOUNT key [start end] | 统计值为 1 的 bit 数量 |
BITOP operation destkey key [key ...] | 对多个 Bitmap 执行位运算(AND/OR/XOR/NOT) |
实战示例:用户签到
# 用户 1000 在 2024-01-01 签到
SETBIT user:sign:1000 20240101 1
# 查询用户 1000 在 2024-01-01 是否签到
GETBIT user:sign:1000 20240101
# 统计用户 1000 总签到天数
BITCOUNT user:sign:1000
Geo 地理位置类型
Redis 的 Geo 类型内部基于 Sorted Set 实现,结合了三项核心技术:Z-order 曲线、Base32 编码与 GeoHash 算法。
Z-Order 曲线
Z-order 曲线是一种空间填充曲线,能将多维数据映射到一维,同时保持空间局部性——地理位置相近的点,在一维编码中也靠近彼此。
编码过程(以坐标 (3, 5) 为例):
- 将 X=3、Y=5 分别转为二进制:
011、101 - 交叉合并各 bit(先 Y 后 X 交替):
011011 - 转为十进制:
27
Base32 编码
Base32 使用 32 个字符(0-9、b-z 去掉易混淆字符)将二进制数据转为可打印 ASCII:
- 将二进制数据拆分为 5-bit 一组
- 每组(0–31)映射到 Base32 字母表
- 末尾不足 5-bit 时补
=填充
GeoHash 算法
GeoHash 将地球上任意位置的经纬度编码为一个紧凑字符串。Redis 内部使用 52-bit 整数存储在 Sorted Set 的 score 中,通过 z-score 排序实现高效的附近查询。
核心命令
# 添加地理位置(经度 纬度 成员名)
GEOADD user:addr 111.11 44.44 ww 112.22 43.33 kk
# 获取 GeoHash 编码
GEOHASH user:addr ww
# 获取坐标
GEOPOS user:addr ww
# 计算两点距离(单位:km)
GEODIST user:addr ww kk km
# 查找附近成员(Redis 6.2+)
GEOSEARCH user:addr FROMMEMBER ww BYRADIUS 100 km ASC
Stream 消息流
Stream 是 Redis 5.0 引入的数据结构,提供持久化消息队列功能,弥补了 Pub/Sub 不能持久化的缺陷。
主要能力
- 自动生成消息 ID(格式:
毫秒时间戳-序号) - 消息遍历与范围查询
- 阻塞/非阻塞读取
- 消费者组(Consumer Group)支持
- Pending 消息确认机制
- 队列监控与消息回溯
核心命令
# 写入消息(* 表示自动生成 ID)
XADD topic:001 * name wzk age 18
# 读取范围消息(- 表示最小 ID,+ 表示最大 ID)
XRANGE topic:001 - +
# 消费消息(从 ID=0 开始读 1 条)
XREAD COUNT 1 STREAMS topic:001 0
# 创建消费者组
XGROUP CREATE topic:001 group1 0
# 消费者组读取
XREADGROUP GROUP group1 consumer1 COUNT 1 STREAMS topic:001 >
# 确认消息
XACK topic:001 group1 <message-id>
与 Pub/Sub 的区别
| 特性 | Stream | Pub/Sub |
|---|---|---|
| 消息持久化 | 支持 | 不支持 |
| 消费确认 | 支持(ACK) | 不支持 |
| 消费者组 | 支持 | 不支持 |
| 历史消息 | 可回溯 | 无法获取 |
Stream 适合对消息可靠性有要求的场景,而 Pub/Sub 更适合实时广播、对丢消息不敏感的场景。