日活统计必须每日更换key,如active:2026-07-13,避免数据污染;user_id需归一化为紧凑offset以防内存浪费;bitcount不支持按用户范围统计,全量统计用bitcount key即可;需用户明细时应配合set等结构。

日活统计必须每天换 key,不能复用同一个 key
直接往一个固定 key(比如 daily_active_users)里反复 setbit,会导致数据污染:昨天的用户状态会和今天混在一起,bitcount 统计的是所有历史置位的总和,不是当日活跃数。
正确做法是把日期嵌入 key 名,例如:active:2026-07-13、play:2026-07-13。用户登录或触发行为时,执行:setbit active:2026-07-13 user_id 1
- key 命名建议带业务前缀(如
login:、view:),避免不同场景冲突 - 日期格式统一用
yyyy-mm-dd,便于按字符串范围扫描或 TTL 设置 - 不要用时间戳做 key 后缀(如
active:1752406500),可读性和运维排查成本高
user_id 直接当 offset 用?先确认是否从 0 开始
Redis 的 setbit 要求 offset 是非负整数,且越界会自动扩容。但很多系统 user_id 是从 100001、888888 这类大数开始的——如果直接传原始 id,会导致 bitmap 前面大量空字节,浪费内存。
例如 user_id = 100001,setbit active:2026-07-13 100001 1 会分配至少 100001/8 ≈ 12.5KB 空间,其中前 12.5KB 几乎全是 0。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 若 user_id 连续且基数小(如内部测试账号 1~10000),可直接用
- 若 user_id 分散或起始值大,应做归一化:减去最小 ID(如
user_id - 100000),或用哈希映射到紧凑区间 - 归一化逻辑必须稳定,否则同个用户不同请求算出不同 offset,统计就乱了
bitcount 性能够快,但别在大 offset 场景下误用 start/end 参数
bitcount key [start] [end] 的 start 和 end 指的是字符串字节索引,不是 bit 位偏移。很多人以为 bitcount active:2026-07-13 0 9999 是统计前 10000 个用户,实际是读取 value 的第 0 到第 9999 字节——这可能只覆盖前 8 万个 bit,也可能根本没覆盖目标用户。
日常统计全量日活,直接用 bitcount active:2026-07-13 就行,复杂度 O(N),N 是底层字符串长度,但 Redis 内部做了优化,百万级用户通常几毫秒内返回。
- 需要查某段用户区间(如 uid 10000–19999)时,不要依赖
bitcount的 range 参数 - 要么提前归一化 offset 范围,让目标用户落在低偏移区;要么用
get拿出整个 bitmap,客户端解析(适合离线批处理) - 高频实时查询建议加缓存,比如定时每 5 分钟跑一次
bitcount,结果写入另一个 key
bitmap 不是万能的,别在需要精确用户列表时硬扛
bitcount 只返回数字,没法告诉你“哪些用户活跃”。如果业务需要导出今日活跃 UID 列表、做二次画像或推送,bitmap 本身不支持反查 —— 它没有索引,只能逐 bit getbit 扫描,O(N) 时间且不可并发加速。
这时候得搭配其他结构:比如同时往 set 里 sadd active_set:2026-07-13 user_id,或者用 hyperloglog 做去重基数 + set 存明细。
- 纯数字指标(DAU、WAU、留存率)→ bitmap 是最优解
- 要用户明细、要分群、要关联其他属性 → bitmap 只适合做第一层快速过滤,后面必须接其他存储
- 注意
set内存开销比 bitmap 高一个数量级,别无脑替换










