【Redis】 高级类型与布隆过滤器 原理+场景全解析
大家好,我是程序员二叉。
简介
本文详细讲解 Redis 四大高级功能:HyperLogLog、Bitmap、Geo、Stream,以及面试高频考点布隆过滤器。涵盖底层原理、使用场景、核心区别、实战要点,是后端进阶与面试必备干货。欢迎点赞收藏关注。
一、HyperLogLog:基数统计神器
1. 核心作用
只做一件事:统计一个集合中不重复元素的个数(基数统计)。
例如:统计网站 UV、独立访客数、每日活跃设备数。
2. 误差范围
- 标准误差率:0.81%(极小误差)。
- 内存占用:极小!每个 Key 最多占用12KB内存,无论统计 1000 条还是 10 亿条数据。
3. 优缺点
- 优点:内存占用极低、速度极快、支持合并统计。
- 缺点:只能统计数量,不能获取原始数据,存在微小误差。
4. 核心命令
PFADD key element:添加元素PFCOUNT key:统计基数
5. 适用场景
- 页面UV(独立访客)统计
- 日活、月活用户数(DAU/MAU)
- 海量数据去重计数(不要求 100% 精确)
二、Bitmap 位图:二进制状态存储
1. 底层原理
- 本质是一串连续的二进制数组(0 和 1),底层基于 String 实现。
- 一个 bit 位代表一个状态,极大节省内存。
- 1MB 内存 = 800 万 bit,可以记录 800 万个状态。
2. 核心命令
SETBIT key offset value:设置第 offset 位的值(0/1)GETBIT key offset:获取状态BITCOUNT key:统计有多少个 1
3. 经典场景:用户签到
- Key 设计:
sign:user:1001:202505 - Offset:日期(1~31)
- Value:1=已签到,0=未签到
- 优势:一个用户一个月仅占用31 bit(约4字节)。
4. 经典场景:统计活跃用户
- Key 设计:
active:20250501 - Offset:用户 ID
- 统计:
BITCOUNT算出当日活跃人数。 - 多日统计:
BITOP做与/或运算,算出连续活跃天数。
三、Geo 地理位置:附近的人/店
1. 实现原理
- 底层就是 ZSet(有序集合)。
- 使用GeoHash 算法将二维经纬度(经度、纬度)编码成一个分数 score。
- 利用 ZSet 的排序特性,实现范围查找。
2. 核心命令
GEOADD key 经度 纬度 成员:添加位置GEODIST key 成员1 成员2:计算距离GEORADIUS key 经度 纬度 半径:查找附近元素
3. 适用场景
- 附近的人、附近的门店
- 外卖配送范围、网约车距离计算
- 同城推荐
四、Stream:专业消息队列
1. 核心原理
Redis 5.0 专为消息队列设计的数据结构,支持:持久化、多消费者、消息回溯、堆积。
2. 核心概念
消息 ID(偏移量)
- 格式:
时间戳-序号(如 1712345678900-5)。 - 全局唯一、单调递增,代表消息的偏移量(Offset)。
- 消费者通过 ID 确认消费位置,防止消息丢失。
- 格式:
消费组(Consumer Group)
- 一个队列可以被多个消费组监听,各组互不影响。
- 同一组内消费者负载均衡,一条消息只会被组内一个消费者消费。
- 内置待确认列表(pending),确保消息被成功处理。
3. 核心命令
XADD:生产消息XREADGROUP:消费组消费XACK:确认消息(标记已消费)
4. 优势
- 消息持久化,重启不丢失。
- 支持堆积,百万消息无压力。
- 消费组 + 偏移量,实现可靠消息投递。
五、Bitmap vs HyperLogLog 核心区别
| 特性 | Bitmap | HyperLogLog |
|---|---|---|
| 存储内容 | 存储具体状态(0/1) | 只存储统计算法,不存原始数据 |
| 精准度 | 100% 精准 | 有 0.81%误差 |
| 功能 | 可查单个状态、统计总数 | 只能查总数 |
| 内存 | 取决于用户量(N bit) | 固定 12KB |
| 典型场景 | 签到、是否在线、状态标记 | UV、日活、去重计数 |
一句话总结
- 需要查单个用户状态用Bitmap。
- 只需要统计总人数且省内存用HyperLogLog。
六、布隆过滤器(Bloom Filter):缓存穿透杀手
1. 核心原理
- 由一个超大的二进制数组 + 多个哈希函数组成。
- 添加元素时,通过多个 Hash 算法算出多个位置,把这些位置置为 1。
- 查询元素时,检查这些位置是否全为 1。
2. 优缺点
- 优点:内存占用极小、查询速度 O(1)、判断存在性高效。
- 缺点:
- 有误判率:判断存在的,可能不存在(假阳性)。
- 无法删除:置 1 容易,清零难。
3. 误判问题
- 一定会误判,但可以通过调大数组、增加 Hash 函数降低误判率。
- 对策:
- 允许一定误判,容忍小概率错误。
- 误判后请求数据库,数据库返回空则直接返回。
4. 核心使用场景
解决缓存穿透问题(大量查询不存在的数据,直接打穿到数据库)。
- 把数据库已存在的 ID提前放入布隆过滤器。
- 查询时先查过滤器:
- 不存在 → 直接返回,不放行到数据库。
- 存在 → 再查缓存/数据库。
总结
- HyperLogLog:海量数据去重计数,省内存,有 0.81% 误差。
- Bitmap:状态标记(签到/活跃),精准,存 0/1。
- Geo:基于ZSet + GeoHash,实现附近位置服务。
- Stream:专业MQ,靠偏移量定位,消费组负载均衡。
- 布隆过滤器:判断不存在绝对准确,防缓存穿透神器。
