第六章 高级数据类型 v1.0
一、基数统计(HyperLogLog)
HyperLogLog 是 Redis 2.8.9 版本引入的数据结构,用于基数统计(统计一个集合中不重复元素的个数)。
传统方案比如用 Set 存储,会随着数据量增大占用大量内存。HyperLogLog 只需要固定 12KB 内存就能统计接近 2^64 个不同元素的基数。
1.基本命令
bash
# 添加元素(本质是记录,不存储元素本身)
PFADD key element [element ...]
# 返回基数估算值
PFCOUNT key [key ...]
# 合并多个 HyperLogLog 到一个 key
PFMERGE destkey sourcekey [sourcekey ...]2.特点
- 统计结果有 0.81% 的标准误差
- 不存储元素本身,只存储基数
- 固定 12KB 内存,适合大数据量的去重统计
3.适用场景
- 统计网站 UV(独立访客数)
- 统计每日活跃用户数
二、发布订阅(Pub/Sub)
Redis 的 Pub/Sub 是一种消息通信模式:发送者(Publisher)发送消息,订阅者(Subscriber)接收消息。
1.基本命令
bash
# 订阅一个或多个频道
SUBSCRIBE channel [channel ...]
# 向频道发送消息
PUBLISH channel message
# 订阅符合模式的频道(如 news.* 匹配 news.sport、news.tech 等)
PSUBSCRIBE pattern [pattern ...]
# 退订频道
UNSUBSCRIBE [channel [channel ...]]
# 退订模式
PUNSUBSCRIBE [pattern [pattern ...]]2.使用示例
bash
# 终端1:订阅 news 频道
SUBSCRIBE news
# 终端2:向 news 频道发送消息
PUBLISH news "Hello Redis Pub/Sub"
# 返回值为订阅者数量3.注意事项
- 消息不会持久化,没有订阅者的消息会丢失
- 不支持消费者组和消息确认,生产环境建议使用 Stream
- 客户端断开连接后,订阅自动取消
三、地理空间(Geo)
Redis 3.2 版本引入了 Geo 类型,用于存储地理位置信息,底层使用 Sorted Set 实现。
1.基本命令
bash
# 添加地理位置(经度、纬度、名称)
GEOADD key longitude latitude member [longitude latitude member ...]
# 获取指定名称的经纬度
GEOPOS key member [member ...]
# 计算两个位置之间的距离
GEODIST key member1 member2 [m|km|ft|mi]
# 以给定经纬度为中心,查找指定半径内的成员
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [COUNT count]
# 以某个成员为中心,查找指定半径内的成员
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [COUNT count]
# 返回 geohash 字符串
GEOHASH key member [member ...]
# 删除地理位置
ZREM key member [member ...]2.使用示例
bash
# 添加几个城市的位置
GEOADD cities 116.40 39.90 "北京"
GEOADD cities 121.47 31.23 "上海"
GEOADD cities 113.26 23.13 "广州"
# 计算北京到上海的距离
GEODIST cities "北京" "上海" km
# 查找距离北京 1500km 内的城市
GEORADIUSBYMEMBER cities "北京" 1500 km WITHDIST3.注意事项
- 经度范围:-180 ~ 180,纬度范围:-85.05112878 ~ 85.05112878
- 底层是 Sorted Set,可以用
ZREM删除成员 - 直接两极附近的坐标可能会有精度问题
四、位图(BitMap)
BitMap 不是一种独立的数据类型,而是基于 String 类型的一组按位操作命令。适合用一个 bit 位来表示某个元素的状态值。
1.基本命令
bash
# 设置指定偏移量的值(0 或 1)
SETBIT key offset value
# 获取指定偏移量的值
GETBIT key offset
# 统计值为 1 的 bit 数量
BITCOUNT key [start end]
# 对多个 key 做位运算(AND、OR、XOR、NOT)
BITOP AND|OR|XOR|NOT destkey key [key ...]
# 返回第一个值为 0 或 1 的 bit 位
BITPOS key 0|1 [start] [end]2.使用示例
bash
# 用 BitMap 记录用户签到(offset = 用户ID,第 7 天)
SETBIT sign:user1001:2024-01 6 1
# 查询用户第 7 天是否签到
GETBIT sign:user1001:2024-01 6
# 统计本月签到天数
BITCOUNT sign:user1001:2024-01
# 统计多个用户的签到情况
BITOP AND sign:common user1:user2:sign user2:user2:sign3.适用场景
- 用户签到打卡
- 统计活跃用户(每天一个 key,bit 位对应用户 ID)
- 布尔值的高效存储(如权限开关)
五、流(Stream)
Stream 是 Redis 5.0 引入的消息队列数据类型,支持消费者组和消息确认,可以看作是 Pub/Sub 的增强版。
1.基本命令
bash
# 添加消息(* 表示自动生成 ID)
XADD key ID field value [field value ...]
# 读取消息
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
# 创建消费者组
XGROUP CREATE key groupname ID [MKSTREAM]
# 消费者组读取消息
XREADGROUP GROUP groupname consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] ID [ID ...]
# 确认消息已被处理
XACK key groupname ID [ID ...]
# 获取 Stream 信息
XINFO STREAM key
# 获取消费者组信息
XINFO GROUPS key
# 删除消息
XDEL key ID [ID ...]
# 裁剪 Stream 长度
XTRIM key MAXLEN [~] count2.使用示例
bash
# 添加消息
XADD mystream * name "John" action "login"
# 读取最新消息
XREAD COUNT 10 STREAMS mystream 0
# 创建消费者组(从最新消息开始消费)
XGROUP CREATE mystream mygroup $
# 消费者组读取消息
XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >
# 确认消息处理完成
XACK mystream mygroup 1234567890-03.与 Pub/Sub 的对比
| 对比项 | Pub/Sub | Stream |
|---|---|---|
| 消息持久化 | 不支持 | 支持 |
| 消费者组 | 不支持 | 支持 |
| 消息确认 | 不支持 | 支持(XACK) |
| 历史消息回溯 | 不支持 | 支持 |
| 适用场景 | 简单通知 | 生产环境消息队列 |
六、位域(BitField)
BitField 命令允许在一个 String 类型的 key 中操作多个位域,支持自定义位宽的有符号/无符号整数的读写和自增操作。
1.基本命令
bash
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]type:u+ 位数(无符号)或i+ 位数(有符号),如u8表示 8 位无符号整数,i16表示 16 位有符号整数offset:位偏移量OVERFLOW:溢出策略WRAP:回绕(默认)SAT:饱和(到最大/最小值后停止)FAIL:溢时不执行
2.使用示例
bash
# 设置一个无符号 8 位整数(偏移量 0),值为 200
BITFIELD mykey SET u8 0 200
# 读取该值
BITFIELD mykey GET u8 0
# 自增 10
BITFIELD mykey INCRBY u8 0 10
# 使用 SAT 溢出策略,防止溢出回绕
BITFIELD mykey OVERFLOW SAT SET u8 0 250
BITFIELD mykey OVERFLOW SAT INCRBY u8 0 10
# 结果为 255(不会溢出到 4)3.适用场景
- 紧凑存储多个小整数(如计数器、状态标志)
- 节省内存的统计数据存储