Redis 数据类型在商超的使用场景及详细分析
1. 各数据类型在商超环境的核心使用场景总述
1.1. String 类型
1.2. Hash 类型
1.3. List 类型
1.4. Set 类型
1.5. Sorted Set 类型
1.6. Bitmap 类型
1.7. HyperLogLog 类型
2. 获取数据类型与时间复杂度说明
2.1 时间复杂度说明
- O(1):操作时间与数据量无关,性能最优(如 String 的 GET/SET、Hash 的 HGET)。
- O(log n):操作时间随数据量对数增长,适合大数据量场景(如 Sorted Set 的 ZADD/ZRANK)。
- O(n):操作时间随数据量线性增长,需控制数据规模(如 List 的 LRANGE、Set 的 SADD 多元素)。
- O(k):操作时间取决于返回 / 处理的元素数量 k(如 List 的 LRANGE 返回 k 个元素)。
2.2 查询不同键的类型
2.3 获取 DB 中的键列表
用法:SCAN 游标 [MATCH 模式] [COUNT 数量]
3. Redis String 类型操作分类详解
3.1. 基础设值与取值操作
3.2. 批量操作
3.3. 数值操作(自增 / 自减)
3.4. 字符串操作(长度、追加、子串)
3.5. 位操作(String 底层是字节数组,支持位级操作)
4. Redis Hash 类型操作分类详解
4.1. 基础设值与取值操作
4.2. 批量操作
4.3. 字段操作(删除、长度、数值增减)
4.4. 其他操作(迭代、设置过期)
4.5. 关键说明
5. Redis List 类型操作详解
以下是 Redis List 类型的操作分类列表,按照操作类型进行了系统性的整理:
5.1. 元素添加操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 左端推入 | LPUSH orders uid:1001 |
将一个或多个值插入到列表头部 | 新订单加入处理队列头部,优先处理 | 批量操作时使用 LPUSH key elem1 elem2 elem3 |
O(1) 每个元素 | 否 |
| 右端推入 | RPUSH orders uid:1002 |
将一个或多个值插入到列表尾部 | 新订单加入处理队列尾部,排队处理 | 同上,使用批量操作减少网络往返 | O(1) 每个元素 | 否 |
| 插入元素 | LINSERT orders BEFORE "uid:1002" "uid:1005" |
在指定元素前/后插入新元素 | 高优先级订单插入到普通订单前面 | 需要遍历列表,性能较差 | O(N) | 否 |
5.2. 元素移除操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 左端弹出 | LPOP orders |
移除并返回列表头部元素 | 从订单队列头部取出订单处理 | 处理 nil 结果,避免空轮询 |
O(1) | 否 |
| 右端弹出 | RPOP orders |
移除并返回列表尾部元素 | 从订单队列尾部取出订单处理 | 同上 | O(1) | 否 |
| 指定移除 | LREM orders 2 "uid:1001" |
移除列表中与指定值相等的元素 | 用户取消订单,从队列中移除 | 需要遍历列表,性能与列表长度成正比 | O(N) | 否 |
| 修剪列表 | LTRIM recent_orders 0 99 |
只保留指定区间内的元素 | 只保留最近100条订单记录 | 控制列表长度,防止内存无限增长 | O(N) | 否 |
5.3. 阻塞操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 阻塞左端弹出 | BLPOP order_queue 30 |
列表为空时阻塞连接,直到超时或有元素 | 订单处理worker等待新订单 | 设置合理超时时间,避免无限阻塞 | O(1) | 是 |
| 阻塞右端弹出 | BRPOP order_queue 30 |
同上,但从右端弹出 | 同上 | 同上 | O(1) | 是 |
| 阻塞弹出并推入 | BRPOPLPUSH src_queue dst_queue 30 |
从源列表弹出元素并推入目标列表,阻塞版本 | 处理订单后将其移动到已处理队列 | 原子操作,保证数据不丢失 | O(1) | 是 |
5.4. 查询操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 获取范围 | LRANGE orders 0 4 |
返回列表中指定区间内的元素 | 查看接下来要处理的5个订单 | 避免获取整个大列表 | O(S+N) | 否 |
| 获取指定索引元素 | LINDEX orders 0 |
通过索引获取列表中的元素 | 查看队列中最优先的订单 | 需要遍历列表,性能较差 | O(N) | 否 |
| 获取列表长度 | LLEN orders |
返回列表的长度 | 查看当前待处理订单数量 | 1. 高效查询:该命令时间复杂度为 O(1),可以高频调用而无性能压力。 2. 业务逻辑处理:客户端需处理返回值为 0 的情况(即队列为空或Key不存在)。 |
O(1) |
5.5. 高级操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 弹出并推入 | RPOPLPUSH src_queue dst_queue |
原子性地从源列表尾部弹出元素并推入目标列表头部 | 处理完订单后移动到已完成队列 | 原子操作,保证数据一致性 | O(1) | 否 |
| 设置指定索引值 | LSET orders 0 "uid:1005" |
通过索引设置列表元素的值 | 修改队列中某个订单的优先级 | 需要确保索引不超过列表长度 | O(N) | 否 |
5.6. List 类型应用模式总结
-
栈(Stack)结构:
-
后进先出(LIFO):
LPUSH+LPOP或RPUSH+RPOP
-
-
队列(Queue)结构:
-
先进先出(FIFO):
LPUSH+RPOP或RPUSH+LPOP -
阻塞队列:
LPUSH+BRPOP(最常用)
-
-
有限集合(Capped Collection):
-
LPUSH+LTRIM实现固定长度的列表,如最新N条记录
-
-
消息队列:
-
使用阻塞操作(
BLPOP/BRPOP)实现高效的消息传递 -
使用
RPOPLPUSH实现安全队列(处理中的消息移到另一列表)
-
-
循环列表:
-
RPOPLPUSH同一列表可实现循环列表效果
-
Redis List 的阻塞操作是其独特优势,特别适合实现消息队列、任务队列等场景,能够有效避免客户端的无效轮询,提升系统效率。
6. Redis Set 类型操作详解
Set 是 Redis 中的无序集合,它包含不重复的字符串元素。Set 提供了高效的成员检查、交集、并集、差集等操作,非常适合需要处理唯一性数据的场景。
以下是 Redis Set 类型的操作分类列表:
6.1. 元素添加操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 添加元素 | SADD daily:visitors "user:123" |
向集合添加一个或多个成员 | 记录每日到店访客ID | 批量添加时使用 SADD key member1 member2 |
O(1) 每个元素 | 否 |
| 移动元素 | SMOVE source_set target_set "member" |
将元素从源集合移动到目标集合 | 将VIP客户从普通客户集移动到VIP客户集 | 原子操作,保证数据一致性 | O(1) | 否 |
6.2. 元素移除操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 移除元素 | SREM daily:visitors "user:123" |
移除集合中一个或多个成员 | 从访客记录中移除无效用户 | 批量移除时使用 SREM key member1 member2 |
O(1) 每个元素 | 否 |
| 随机弹出 | SPOP products:viewed:user456 |
随机移除并返回集合中的一个元素 | 从用户浏览历史中随机移除一条记录 | 可指定弹出数量 SPOP key count |
O(1) | 否 |
6.3. 查询操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 获取所有成员 | SMEMBERS vip:customers |
返回集合中的所有成员 | 获取所有VIP客户列表 | 慎用大集合,可能阻塞Redis | O(N) | 否(但可能影响性能) |
| 随机获取元素 | SRANDMEMBER daily:visitors |
随机返回集合中一个或多个元素 | 随机抽取一名幸运访客 | 可指定返回数量 SRANDMEMBER key count |
O(1) | 否 |
| 检查成员存在 | SISMEMBER vip:customers "user:789" |
判断元素是否是集合的成员 | 检查用户是否是VIP客户 | O(1) | 否 | |
| 获取集合大小 | SCARD daily:visitors |
获取集合的成员数 | 统计每日访客数量 | O(1) | 否 |
6.4. 集合运算操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 交集 | SINTER set1 set2 |
返回所有给定集合的交集 | 找出既是老客户又是VIP客户的用户 | 对多个集合求交时复杂度较高 | O(N*M) | 否 |
| 交集存储 | SINTERSTORE result_set set1 set2 |
将交集结果存储到新集合 | 创建"老客户且是VIP"的新集合 | 避免传输大量结果数据 | O(N*M) | 否 |
| 并集 | SUNION set1 set2 |
返回所有给定集合的并集 | 合并本周和上周的所有访客 | 对多个集合求并时复杂度较高 | O(N) | 否 |
| 并集存储 | SUNIONSTORE result_set set1 set2 |
将并集结果存储到新集合 | 创建"两周所有访客"的新集合 | 避免传输大量结果数据 | O(N) | 否 |
| 差集 | SDIFF set1 set2 |
返回第一个集合与其他集合的差集 | 找出本周新增的访客(本周-上周) | 对多个集合求差时复杂度较高 | O(N) | 否 |
| 差集存储 | SDIFFSTORE result_set set1 set2 |
将差集结果存储到新集合 | 创建"本周新增访客"集合 | 避免传输大量结果数据 | O(N) | 否 |
6.5. 迭代操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 迭代集合 | SSCAN vip:customers 0 MATCH "user:*" COUNT 100 |
增量迭代集合中的元素 | 分批处理VIP客户数据 | 替代SMEMBERS处理大集合 |
每次调用O(1) | 否 |
6.6 Set 类型应用模式总结
-
唯一性数据存储:
-
用户标签、用户权限、IP黑名单等需要保证唯一性的数据
-
-
关系表示:
-
用户-商品收藏关系、用户-用户关注关系等
-
-
随机抽取:
-
抽奖系统、随机推荐等场景
-
-
数据过滤与统计:
-
使用集合运算进行数据筛选和统计分析
-
-
共同特征查找:
-
查找具有共同特征的用户或物品
-
Set 类型的优势在于其O(1)时间复杂度的添加、删除和查找操作,以及强大的集合运算能力。但需要注意,对于非常大的集合,SMEMBERS命令可能会消耗大量内存和网络资源,此时应使用SSCAN命令进行增量迭代。
Set 类型的所有操作都是非阻塞的,但集合运算操作(如SINTER、SUNION等)在处理大型集合时可能会消耗较多CPU资源,影响Redis的响应性能。
7. Redis Sorted Set 类型操作详解
Sorted Set(有序集合)是 Redis 中一个非常强大的数据结构,它类似于 Set,但每个成员都关联一个分数(score),使得成员可以按照分数进行排序。Sorted Set 同时具有集合的唯一性和有序性特点。
以下是 Redis Sorted Set 类型的操作分类列表:
7.1. 元素添加/更新操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 添加元素 | ZADD product:ranking 1520 "product:1001" |
向有序集合添加一个或多个成员,或更新已存在成员的分数 | 记录商品热度分数 | 批量添加时使用 ZADD key score1 member1 score2 member2 |
O(log N) 每个元素 | 否 |
| 增量更新 | ZINCRBY product:ranking 50 "product:1001" |
增加成员的分数 | 增加商品的点击热度 | 原子操作,避免先ZSCORE再ZADD | O(log N) | 否 |
7.2. 元素移除操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 移除元素 | ZREM product:ranking "product:1001" |
移除有序集合中的一个或多个成员 | 下架商品,从排行榜移除 | 批量移除时使用 ZREM key member1 member2 |
O(M*log N) M为成员数 | 否 |
| 按排名移除 | ZREMRANGEBYRANK product:ranking 0 4 |
移除指定排名区间内的所有成员 | 清空排行榜前5名 | 谨慎使用,会删除多个元素 | O(log N + M) | 否 |
| 按分数移除 | ZREMRANGEBYSCORE product:ranking 0 100 |
移除指定分数区间内的所有成员 | 移除热度低于100的商品 | 同上,注意影响范围 | O(log N + M) | 否 |
7.3. 查询操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 获取分数 | ZSCORE product:ranking "product:1001" |
返回成员的分数值 | 查询某个商品的当前热度 | O(1) | 否 | |
| 获取排名 | ZRANK product:ranking "product:1001" |
返回成员在有序集合中的排名(升序) | 查询商品在排行榜中的位置 | O(log N) | 否 | |
| 获取逆序排名 | ZREVRANK product:ranking "product:1001" |
返回成员在有序集合中的排名(降序) | 查询商品在排行榜中的位置(从高到低) | O(log N) | 否 | |
| 获取集合大小 | ZCARD product:ranking |
获取有序集合的成员数量 | 统计排行榜中商品总数 | O(1) | 否 | |
| 统计分数区间 | ZCOUNT product:ranking 100 500 |
计算指定分数范围内的成员数量 | 统计热度在100-500之间的商品数量 | O(log N) | 否 |
7.4. 范围查询操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 按排名范围查询 | ZRANGE product:ranking 0 9 WITHSCORES |
通过索引区间返回有序集合成员(升序) | 获取排行榜前10名商品 | 使用WITHSCORES同时返回分数 | O(log N + M) | 否 |
| 按排名范围逆序查询 | ZREVRANGE product:ranking 0 9 WITHSCORES |
通过索引区间返回有序集合成员(降序) | 获取排行榜前10名商品(从高到低) | 同上 | O(log N + M) | 否 |
| 按分数范围查询 | ZRANGEBYSCORE product:ranking 100 500 WITHSCORES |
通过分数返回有序集合成员 | 获取热度在100-500之间的所有商品 | 可结合LIMIT分页 | O(log N + M) | 否 |
| 按分数范围逆序查询 | ZREVRANGEBYSCORE product:ranking 500 100 WITHSCORES |
通过分数返回有序集合成员(降序) | 获取热度在100-500之间的所有商品(从高到低) | 同上 | O(log N + M) | 否 |
7.5. 集合运算操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 交集存储 | ZINTERSTORE result 2 set1 set2 WEIGHTS 2 3 |
计算多个有序集合的交集并存储结果 | 合并多个商品排行榜 | 可以设置权重和聚合方法 | O(NK)+O(Mlog M) | 否 |
| 并集存储 | ZUNIONSTORE result 2 set1 set2 WEIGHTS 2 3 |
计算多个有序集合的并集并存储结果 | 合并多个商品排行榜 | 同上 | O(N)+O(M*log M) | 否 |
7.6. 弹出操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 弹出最高分 | ZPOPMAX product:ranking 5 |
移除并返回分数最高的成员 | 获取并移除热度最高的5个商品 | Redis 5.0+ 支持 | O(log N * M) | 否 |
| 弹出最低分 | ZPOPMIN product:ranking 5 |
移除并返回分数最低的成员 | 获取并移除热度最低的5个商品 | Redis 5.0+ 支持 | O(log N * M) | 否 |
| 阻塞弹出最高分 | BZPOPMAX queues 30 |
阻塞式弹出最高分成员 | 从多个优先级队列中获取最高优先级任务 | Redis 5.0+ 支持 | O(log N) | 是 |
| 阻塞弹出最低分 | BZPOPMIN queues 30 |
阻塞式弹出最低分成员 | 从多个优先级队列中获取最低优先级任务 | Redis 5.0+ 支持 | O(log N) | 是 |
7.7. 迭代操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 迭代集合 | ZSCAN product:ranking 0 MATCH "product:1*" COUNT 100 |
增量迭代有序集合中的元素 | 分批处理特定类型的商品数据 | 替代ZRANGE处理大集合 | 每次调用O(1) | 否 |
7.8 Sorted Set 类型应用模式总结
-
排行榜系统:
-
商品热度榜、用户积分榜、销售排行榜等
-
-
优先级队列:
-
任务调度系统,按优先级处理任务
-
-
范围查询:
-
按分数范围查询数据,如查询价格在某个区间的商品
-
-
时间轴数据:
-
使用时间戳作为分数,存储按时间排序的数据
-
-
带权重的集合运算:
-
复杂的排行榜合并和计算
-
Sorted Set 类型的优势在于其既能保证元素的唯一性,又能按照分数进行排序,同时提供了丰富的范围查询和集合运算功能。需要注意,ZRANGE、ZINTERSTORE等范围操作在处理大量数据时可能会消耗较多资源,应根据实际情况合理使用。
Sorted Set 的阻塞操作(BZPOPMAX/BZPOPMIN)主要用于实现优先级队列的消费者模式,能够在队列为空时阻塞等待,避免无效轮询。
8. Redis Bitmap 类型操作详解
Bitmap(位图)不是独立的数据类型,而是基于 String 类型的一套位操作命令。Bitmap 通过将字符串视为位数组,提供了极其高效的空间利用率和位操作能力,特别适合布尔值统计和标记场景。
以下是 Redis Bitmap 类型的操作分类列表:
8.1. 位设置/清除操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 设置位值 | SETBIT user:sign:202409 15 1 |
对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit) | 记录用户ID为15的用户在2024年9月某天签到 | 偏移量从0开始,最大2³² | O(1) | 否 |
| 清除位值 | SETBIT user:sign:202409 15 0 |
清除指定偏移量上的位(设置为0) | 取消用户的签到记录 | 实际上是SETBIT的值为0 | O(1) | 否 |
8.2. 位查询操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 获取位值 | GETBIT user:sign:202409 15 |
对 key 所储存的字符串值,获取指定偏移量上的位(bit) | 查询用户ID为15的用户在2024年9月某天是否签到 | O(1) | 否 | |
| 获取位图 | GET user:sign:202409 |
获取整个位图的二进制数据 | 导出某天的所有签到数据 | 可能返回大量数据,慎用 | O(1) | 否 |
8.3. 位统计操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 统计置位数 | BITCOUNT user:sign:202409 |
计算给定字符串中,被设置为 1 的比特位的数量 | 统计某天签到的总用户数 | 可指定范围 BITCOUNT key start end |
O(N) | 否 |
| 按位统计 | BITCOUNT user:sign:202409 0 2 |
计算指定字节范围内的置位数 | 统计前3个字节范围内的签到用户数 | 使用字节偏移而非位偏移 | O(N) | 否 |
8.4. 位图运算操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 位与运算 | BITOP AND result user:sign:0901 user:sign:0902 |
对一个或多个位图执行逻辑与操作,结果存到新位图 | 找出9月1日和2日都签到的用户 | 支持AND/OR/XOR/NOT操作 | O(N) | 是(大数据量时) |
| 位或运算 | BITOP OR result user:sign:0901 user:sign:0902 |
对一个或多个位图执行逻辑或操作 | 找出9月1日或2日签到的所有用户 | 同上 | O(N) | 是 |
| 位异或运算 | BITOP XOR result user:sign:0901 user:sign:0902 |
对一个或多个位图执行逻辑异或操作 | 找出只在9月1日或只在9月2日签到的用户 | 同上 | O(N) | 是 |
| 位非运算 | BITOP NOT result user:sign:0901 |
对位图执行逻辑非操作 | 找出9月1日未签到的所有用户 | 同上 | O(N) | 是 |
8.5. 位查找操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 查找第一个置位 | BITPOS user:sign:202409 1 |
返回位图中第一个值为指定bit的二进制位的位置 | 找到第一个签到的用户ID | 可指定查找范围 BITPOS key bit start end |
O(N) | 否 |
| 查找第一个清零位 | BITPOS user:sign:202409 0 |
返回位图中第一个值为0的二进制位的位置 | 找到第一个未签到的用户ID | 同上 | O(N) | 否 |
8.6. 字段位操作(Redis 7.0+)
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 字段位操作 | BITFIELD user:flags GET u4 0 |
对位图进行多个操作,支持整数子字段 | 从位图中提取用户标志位的特定字段 | 强大但复杂,需理解子字段概念 | O(1) 每个子操作 | 否 |
| 字段位设置 | BITFIELD user:flags SET u4 0 5 |
设置位图中特定字段的值 | 设置用户的权限标志位 | 可执行多个操作原子性 | O(1) 每个子操作 | 否 |
| 原子增量 | BITFIELD user:counters INCRBY u8 0 1 |
对位图中的整数字段进行原子增量 | 统计用户访问次数(8位计数器) | 避免竞态条件 | O(1) 每个子操作 | 否 |
8.8 Bitmap 类型应用模式总结
-
用户签到系统:
-
使用
SETBIT/GETBIT记录和查询每日签到 -
使用
BITCOUNT统计月度签到次数
-
-
活跃用户统计:
-
使用位图记录每日活跃用户
-
使用
BITOP计算周/月活跃用户(OR操作) -
使用
BITOP计算连续活跃用户(AND操作)
-
-
布隆过滤器:
-
使用多个位图和哈希函数实现概率型数据结构
-
-
特征标志存储:
-
使用
BITFIELD紧凑存储多个布尔或枚举型特征
-
-
实时数据统计:
-
使用位图进行各种集合运算和统计
-
8.9 重要注意事项
-
内存效率: Bitmap 极其节省内存,10,000,000 用户签到仅需约 1.2MB 内存
-
偏移量限制: 最大偏移量为 2³²(约42亿),足够大多数场景使用
-
阻塞风险:
BITOP操作在大位图时可能阻塞Redis,应在低峰期执行 -
BITFIELD复杂性:
BITFIELD功能强大但学习曲线较陡,需仔细理解数据类型和偏移量
Bitmap 通过极致的空间效率和高效的位操作,为大规模布尔值存储和统计提供了完美的解决方案,特别适合用户行为分析、实时统计等场景。
9. Redis HyperLogLog 类型操作详解
HyperLogLog 是 Redis 中用于基数统计(估算集合中不重复元素数量)的概率算法数据结构。它提供了一种极其节省内存的方式来计算大规模数据的唯一值数量,标准误差约为 0.81%。
以下是 Redis HyperLogLog 类型的操作分类列表:
9.1. 基数添加操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 添加元素 | PFADD daily:uv "user:123" |
将任意数量的元素添加到 HyperLogLog 中 | 记录每日独立访客 | 批量添加元素比多次调用更高效 | O(1) 每个元素 | 否 |
| 批量添加 | PFADD daily:uv "user:123" "user:456" "user:789" |
一次性添加多个元素到 HyperLogLog | 批量记录多个用户的访问 | 减少网络往返次数 | O(N) N为元素数量 | 否 |
9.2. 基数统计操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 基数估算 | PFCOUNT daily:uv |
返回给定 HyperLogLog 的基数估算值 | 统计今日独立访客数量 | 单个key的PFCOUNT非常快 | O(1) | 否 |
| 多键统计 | PFCOUNT day1:uv day2:uv day3:uv |
返回多个 HyperLogLog 的合并基数估算值 | 统计三天内的总独立访客(去重) | 内部会执行合并操作 | O(N) N为key数量 | 否 |
9.3. 数据合并操作
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 合并存储 | PFMERGE weekly:uv mon:uv tue:uv wed:uv |
将多个 HyperLogLog 合并为一个新的 HyperLogLog | 将一周七天的UV数据合并为周UV数据 | 合并后的新HLL可以继续用于统计 | O(N) N为合并的key数量 | 否 |
9.4. 内存优化特性
| 操作类型 | 语法示例 | 关键字说明(操作逻辑) | 商超场景案例 | 优化点 | 时间复杂度 | 是否阻塞 |
|---|---|---|---|---|---|---|
| 内存使用 | (无需命令) | 每个 HyperLogLog 仅占用约 12KB 内存 | 统计亿级用户访问仅需12KB内存 | 固定内存占用,与元素数量无关 | - | - |
9.5 HyperLogLog 类型应用模式总结
-
大规模基数统计:
-
网站独立访客(UV)统计
-
搜索关键词唯一用户数统计
-
广告点击独立用户数统计
-
-
多维度数据合并:
-
按时间维度合并统计数据(日→周→月)
-
按业务维度合并统计数据(不同频道的UV合并)
-
-
实时流量监控:
-
实时统计不同页面的访问用户数
-
监控API调用的独立用户数
-
9.6 HyperLogLog 的重要特性
-
固定内存占用: 每个 HyperLogLog 只需要约 12KB 内存,无论统计多少元素
-
近似计数: 提供概率性估算而非精确计数,标准误差为 0.81%
-
支持合并: 多个 HyperLogLog 可以被合并,合并后的基数估算仍然是准确的
-
非阻塞操作: 所有 HyperLogLog 操作都是非阻塞的,适合高性能场景
9.7 使用限制和注意事项
-
不存储原始数据: HyperLogLog 只存储基数估算信息,无法获取具体的元素内容
-
计数为估算值: 适用于需要大致数量而非精确值的场景
-
适合大规模数据: 对于小规模数据集,使用 Set 可能更合适(可获取具体元素)
-
合并成本: 合并多个 HyperLogLog 时有一定的计算开销,但仍在可控范围内
9.8 商超场景综合案例
# 记录每日独立访客
PFADD 2024-09-08:uv "user:1001" "user:1002" "user:1003"
# 记录每周独立访客(通过合并每日数据)
PFMERGE 2024-09-week:uv 2024-09-01:uv 2024-09-02:uv ... 2024-09-07:uv
# 统计本月独立访客总数
PFCOUNT 2024-09-01:uv 2024-09-02:uv ... 2024-09-30:uv
# 比较不同商品页面的独立访客
PFCOUNT product:1001:uv product:1002:uv product:1003:uv
HyperLogLog 是 Redis 中解决大规模基数统计问题的利器,它以极小的内存开销和可接受的误差率,为亿级数据的唯一值统计提供了完美的解决方案。
posted on
浙公网安备 33010602011771号