文章目录
- 1.引言
- 2.Stream
- 3.Geospatial
- [4. HyperLogLog](#4. HyperLogLog)
- 5.Bitmap
- [6. Bitfields](#6. Bitfields)
- 6.小结
1.引言
Redis 的 String、List、Hash、Set、ZSet 五大基础类型已能覆盖大部分场景,但针对 "消息队列""地理位置""海量去重计数""空间优化存储" 等细分需求,Redis 提供了 5 种特殊数据类型 ------Stream(高级消息队列)、Geospatial(地理位置)、HyperLogLog(海量去重计数)、Bitmap(位图)、Bitfields(位域)。它们虽不像基础类型那样通用,却在各自领域做到了 "高效 + 省空间",是分布式系统中解决特定问题的 "利器"。本文将逐一拆解这 5 种类型的核心特性、命令与应用场景,帮你掌握 "什么时候用、怎么用"。
2.Stream
Stream 是 Redis 5.0 新增的类型,专为 "可靠消息队列" 设计,解决了 List 实现消息队列时 "无消息确认、无重复消费防护" 的痛点,是 Redis 作为消息中间件的核心支撑。
stream就是一个阻塞队列
是redis作为一个消息队列的重要支撑
属于是List blpop / brpop 的升级版本
核心特性
- 消息持久化:Stream 中的消息会持久化到 RDB 和 AOF,Redis 重启后消息不丢失(List 的消息若未手动持久化,重启后可能丢失);
- 消息确认机制:消费者读取消息后需手动 "确认"(ACK),未确认的消息会重新进入待消费队列,避免消息丢失;
- 分组消费:支持多个 "消费组" 同时消费同一个 Stream,每个消费组内可有多个消费者,实现 "消息广播" 与 "负载均衡";
- 阻塞读取:支持类似 Listbrpop的阻塞读取,且能指定 "从最新消息开始读" 或 "从历史消息开始读",灵活应对不同场景。
核心命令
xadd key * field value [field value ...](生产消息)
- 功能:向 Stream 中添加一条消息;*表示让 Redis 自动生成唯一消息 ID(格式为 "时间戳 - 序列号",如1717200000-0);field-value为消息内容(支持多字段,类似 Hash)。
xreadgroup GROUP groupName consumerName COUNT count STREAMS key ID(消费消息)
- 功能:消费组内的消费者读取 Stream 消息;GROUP指定消费组名,consumerName指定消费者名,COUNT指定单次读取条数,ID指定从哪个消息 ID 开始读(>表示读最新未消费消息,0表示读历史消息)。
xack key groupName msgId [msgId ...](确认消息)
- 功能:消费者处理完消息后,向 Stream 确认 "消息已处理",避免消息重新进入待消费队列。
应用场景:可靠消息队列
- 订单状态流转:订单创建后,通过 Stream 发送 "订单待支付" 消息,支付服务消费后处理支付,处理完确认消息;若支付失败,消息不确认,会被重新消费
- 日志收集:多台服务器将日志通过xadd写入 Stream,日志服务通过消费组批量消费日志,实现 "分布式日志集中收集"。
3.Geospatial
Geospatial(简称 GEO)专为存储 "经纬度坐标" 设计,支持 "按距离查找附近地点""按区域查找地点" 等地理相关操作,适用于 "附近的人""周边商户推荐" 等场景。
核心特性:高效处理地理坐标
- 坐标存储:底层通过 Zset 实现(将经纬度编码为score,地点名称为member),支持 O (logN) 的增删查效率;
- 距离计算:支持计算两个地点之间的直线距离(单位可选米、千米、英里等);
- 范围查询:支持两种范围查询 ------"按半径查找圆形区域内的地点""按矩形区域查找范围内的地点"。
核心命令
geoadd key longitude latitude member [longitude latitude member ...](添加地理坐标)
- 功能:向 GEO 类型中添加一个或多个 "经纬度 - 地点" 对;longitude为经度(范围 - 180~180),latitude为纬度(范围 - 90~90),member为地点名称。
georadius key longitude latitude radius m|km|mi|ft [WITHCOORD] [WITHDIST] [COUNT count](按半径查附近地点)
- 功能:以 "指定经纬度" 为中心,查找半径radius范围内的地点;m/km/mi/ft分别表示米、千米、英里、英尺;WITHCOORD返回地点经纬度,WITHDIST返回地点到中心的距离,COUNT限制返回条数

geodist key member1 member2 [m|km|mi|ft](计算两点距离)
- 功能:计算两个地点之间的直线距离,返回距离值(单位默认米)。
应用场景:地理相关需求
- 附近的人:存储用户实时经纬度,通过georadius查找 "以当前用户为中心,1 千米内的其他用户";
- 周边商户推荐:存储商户坐标,用户打开 App 时,查找 "500 米内的餐厅 / 便利店",并按距离排序展示。
4. HyperLogLog
HyperLogLog(简称 HLL)是一种 "概率性数据结构",核心功能只有一个 ------估算集合中的元素个数(去重计数),特点是 "占用空间极小(固定约 12KB),支持海量数据(亿级)",但存在 0.81% 左右的计数误差。
核心特性:用空间换精度,适合海量去重
- 固定空间:无论统计的元素个数是 100 还是 1 亿,HyperLogLog 始终占用约 12KB 内存(对比 Set:1 亿个 8 字节的用户 ID 需 800MB 内存);
- 去重计数:自动实现元素去重,重复添加的元素不会重复计数(如同一用户多次访问,仅计 1 次 UV);
- 概率估算:计数结果存在 0.81% 的误差,适合 "对精度要求不高,对内存敏感" 的场景(如 UV 统计、访问量统计);
- 不存元素:仅记录元素的 "特征"(用于判断是否新元素),无法获取具体元素内容(区别于 Set)。
核心命令
pfadd key element [element ...](添加元素)
- 功能:向 HyperLogLog 中添加一个或多个元素;重复添加的元素会被自动忽略。
pfcount key [key ...](统计元素个数)
- 功能:估算 HyperLogLog 中元素的去重个数;支持同时统计多个 HyperLogLog 的合并个数。
pfmerge destkey sourcekey [sourcekey ...](合并多个 HLL)
- 功能:将多个 HyperLogLog 的元素合并到destkey中,destkey的计数结果为所有源 HLL 的 "去重合并个数"。
应用场景
- UV 统计:统计网站 / APP 的独立访客数(无需精确到个位数,0.81% 误差可接受);
- 搜索关键词去重:统计某段时间内用户搜索的 "不重复关键词个数",无需存储具体关键词;
- 设备去重:统计连接 WiFi 的 "不重复设备数",海量设备场景下节省内存。
5.Bitmap
Bitmap(位图)是一种 "按位存储" 的数据结构,本质是一个二进制字符串(如010110),每个比特位(bit)对应一个 "状态"(0 或 1),支持 "位级别的读写操作",核心优势是 "极致节省空间"(1 字节 = 8 比特,可存储 8 个整数的状态)。
核心特性
- 空间高效:存储 100 万个整数的状态(如 "是否在线"),仅需约 125KB 内存(1000000 / 8 / 1024 ≈ 122KB);
- 位级操作:支持 "设置某比特位的值""获取某比特位的值""统计所有 1 的个数" 等操作,时间复杂度均为 O (1);
- 整数映射:适合存储 "整数型 ID" 的状态(如用户 ID、设备 ID),每个 ID 对应一个比特位(ID 为比特位的下标)。
核心命令
setbit key offset value(设置某比特位的值)
- 功能:设置 Bitmap 中 "下标为offset" 的比特位的值(value为 0 或 1);offset为非负整数(对应整数 ID,如用户 ID=100,offset=100)。
getbit key offset(获取某比特位的值)
- 功能:获取 Bitmap 中 "下标为offset" 的比特位的值(0 或 1);若offset超出当前 Bitmap 长度,返回 0。
bitcount key [start end](统计 1 的个数)
- 功能:统计 Bitmap 中 "所有比特位为 1" 的个数;start和end为字节下标(可选,默认统计所有字节),用于限定统计范围。
应用场景
- 用户在线状态:每个用户 ID 对应一个比特位(如用户 1001 对应offset=1001),1 = 在线,0 = 离线。通过setbit实时更新状态,bitcount快速统计在线人数,getbit查询单个用户状态 ------ 相比用 Set 存储 "在线用户 ID",内存占用降低 8 倍以上。
- 签到功能:用sign:user:1001存储用户 1001 的月度签到记录,offset为日期(1-31),1 = 已签到,0 = 未签到。例如 "3 号签到" 调用setbit sign:user:1001 3 1,月末用bitcount sign:user:1001统计当月签到天数,高效且省空间。
- 数据权限标记:用 Bitmap 存储 "用户对资源的权限",如perm:user:1001中,offset=1表示 "查看权限",offset=2表示 "编辑权限",1 = 拥有权限,0 = 无权限。通过setbit授予 / 收回权限,getbit验证权限,逻辑简洁。
与 HyperLogLog 的区别
两者虽都 "省空间",但核心用途完全不同:
对比维度 | Bitmap | HyperLogLog |
---|---|---|
核心功能 | 存储整数 ID 的 "状态"(0/1),支持查询单个状态 | 估算集合元素个数(去重计数),不存状态 |
数据可读性 | 可通过getbit查询单个 ID 的状态 | 无法查询单个元素是否存在 |
适用场景 | 用户在线、签到、权限标记 | UV 统计、关键词去重计数 |
6. Bitfields
Bitfields(位域)是 Bitmap 的 "进阶版"------ 它将一个二进制字符串(字节数组)拆分为多个 "位段"(Bit Segment),每个位段赋予独立含义(如用 3 位存 "年龄段",2 位存 "性别"),支持对单个位段进行 "读取、修改、算术运算",核心目标是 "在极小空间内存储多维度整数信息"。
核心特性
- 位段自定义:可自由定义每个位段的 "长度" 和 "符号"(无符号 / 有符号),例如用 4 位存 "等级"(0-15),5 位存 "积分"(0-31);
- 多操作批量执行:支持在一个bitfields命令中批量执行多个位段操作(如同时读取 "等级" 和 "积分"),减少网络请求;
- 安全算术运算:对位点段执行 "加 / 减" 时,自动检测溢出并返回溢出状态,避免数据错误(如 3 位无符号位段最大为 7,加 1 溢出时返回溢出标记)。
核心命令
bitfields key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
bitfields是一个 "复合命令",通过子命令(GET/SET/INCRBY)实现不同操作,type表示位段类型(如u3=3 位无符号,i4=4 位有符号),offset表示位段在二进制字符串中的起始位置(从 0 开始)。
6.小结
类型 | 核心功能 | 空间效率 | 典型场景 | 关键限制 |
---|---|---|---|---|
Stream | 高级消息队列,支持 ACK、分组消费 | 中等(按消息条数增长) | 订单状态流转、分布式日志收集 | 不支持消息延迟发送(需额外开发) |
Geospatial | 存储经纬度,支持距离 / 范围查询 | 中等(底层 Zset) | 附近的人、周边商户推荐 | 仅支持二维平面距离计算(不支持海拔) |
HyperLogLog | 海量元素去重计数(估算) | 极高(固定 12KB) | UV 统计、关键词去重计数 | 存在 0.81% 误差,无法查询单个元素 |
Bitmap | 位级存储整数 ID 状态(0/1) | 极高(1 字节存 8 个状态) | 用户在线、签到、权限标记 | 仅支持整数 ID,不适合多维度信息 |
Bitfields | 拆分位段,存储多维度小整数 | 极高(自定义位段长度) | 用户画像、设备状态、游戏属性 | 位段长度有限(最大 64 位),适合小整数 |
Redis 的五大特殊类型,本质是针对 "细分场景" 的 "专精工具"------ 它们不像 String、Hash 那样通用,却在各自领域做到了 "效率与空间的极致平衡":
- Stream 解决了 "可靠消息队列" 的痛点,让 Redis 能替代轻量级中间件;
- Geospatial 让 Redis 具备 "地理计算" 能力,无需依赖专门的地理数据库;
- HyperLogLog 用 12KB 搞定亿级去重计数,突破内存限制;
- Bitmap 和 Bitfields 则将 "位操作" 用到极致,在小空间内存储更多信息。
使用这些特殊类型时,关键是 "不滥用"------ 先明确业务需求是否属于它们的 "专精领域",再结合空间、精度、操作成本选择。