如何用Redis Bitmap快速定位千万级活跃用户中的非活跃留存用户?

陌辰君_8758

陌辰君_8758

2026-10-20

180人浏览

原创

结论:用 bitop not + bitcount 组合可在毫秒级筛出未活跃用户,但需用户 id 映射为连续非负整数偏移且最大 id ≤ 2³²−1;set 和 hyperloglog 无法支持“非活跃”筛选,因前者需全量差集开销大,后者不存原始 id;bitmap 的 not 运算天然适用,但要求位图长度严格对齐真实用户空间,否则稀疏 id 会导致空位翻转虚高结果;key 设计须使 offset = 用户 id(或经映射的连续整数),超限会报错;执行流程为:① setbit 扩容至最大 offset,② bitop not 翻转,③ bitcount 指定字节范围统计;导出具体 id 建议应用层处理;需每日 del 清理过期 key,避免内存膨胀与 not 结果失真。

如何用redis bitmap快速定位千万级活跃用户中的非活跃留存用户?

直接说结论:用 BITOP NOT + BITCOUNT 组合,能在毫秒级完成“从千万活跃用户中筛出未活跃者”,但前提是你的位图 key 已按用户 ID 映射为连续非负整数偏移量,且最大 ID ≤ 2³²−1。

为什么不能直接用 SET 或 HyperLogLog 做“非活跃”筛选

SET 存的是完整字符串,查“不在集合里的用户”必须遍历全量用户池再做差集,IO 和内存开销爆炸;HyperLogLog 根本不存原始 ID,只估算基数,连“谁没来”都无从得知。而 Bitmap 天然支持 NOT 运算——它把整个位数组翻转,0 变 1、1 变 0,再统计 1 的个数,就是非活跃人数。

但注意:NOT 操作会作用于整个底层字符串(即所有已分配字节),所以如果用户 ID 稀疏(比如最大 ID 是 1000 万但只用了其中 50 万个),位图实际长度仍是 1000 万 bit,BITOP NOT 后会把中间大量空闲位也翻成 1,导致结果虚高。必须控制偏移范围。

key 设计与 offset 映射必须对齐业务 ID 空间

假设你有 1000 万注册用户,ID 范围是 1~10000000,那么当天活跃位图的 key 可设为 active:20261019,每个用户 ID 直接作为 offset(ID=1 → offset=1,ID=10000000 → offset=10000000)。

若 ID 是 UUID 或雪花 ID,必须先做映射:

  • 用 MySQL 或 Redis Hash 建 user_id_map 表,把 UUID → 自增整数 ID,写入时同步维护
  • 或用布隆过滤器 + 分段哈希预分配槽位,避免运行时冲突
  • offset 必须 ≥ 0 且 ≤ 4294967295(2³²−1),超限会报错 ERR bit offset is not an integer or out of range

执行非活跃用户定位的三步命令流

以“查 2026-10-19 当天未活跃的用户”为例(假定总用户数 N = 10000000):

① 先确保位图长度覆盖全部用户:向 active:20261019 的第 10000000 位写一个 0(不改变原状态,仅扩容):
SETBIT active:20261019 10000000 0

redis-tools
redis-tools

按类别查找Redis命令、检测服务器连接、监控键数量和内存占用,支持离线速查表。

下载

② 执行翻转,结果存到临时 key:
BITOP NOT inactive:20261019 active:20261019

③ 统计非活跃人数(注意限定字节范围,避免统计高位空字节):
BITCOUNT inactive:20261019 0 1249999(10000000 bit ÷ 8 = 1250000 字节,start=0, end=1249999)

如果要导出具体非活跃用户 ID,得用 BITPOS inactive:20261019 1 循环扫描,但千万级下不建议——应用层拉取再过滤更可控。

容易被忽略的 TTL 和内存清理陷阱

Bitmap 不像普通 String 那样能靠 EXPIRE 自动释放空间:一旦某位被设为 1,即使后续没再更新,该位所在的字节就一直占内存。长期运行后,active:20261019 可能残留大量历史零散置位,导致 NOT 结果膨胀。

必须配合策略:

  • 每日凌晨用 DEL active:YYYYMMDD 清理过期 key(不要依赖 TTL,因为 SETBIT 不会重置 TTL)
  • 对长期留存分析,用新 key 做 BITOP OR 合并多日数据,旧 key 立即删掉
  • 监控 MEMORY USAGE active:*,单 key 超 10MB 就要检查是否出现 ID 映射错乱或异常大 offset

真正难的不是命令怎么敲,而是让 offset 始终紧贴真实用户 ID 空间——漏一位、错一位,NOT 出来的就全是噪声。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

2025.09.05

570

5

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.16

343

7

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

2025.11.17

513

20

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.27

283

6

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4529

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

4075

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

7572

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

643

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

756

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习