java中用redis bitmap实现用户签到和活跃统计,核心是将用户每日行为映射为bit位,通过setbit、getbit、bitcount、bitop等命令操作,配合“sign:uid:{userid}:yyyymm”等合理key设计,以极低内存支持亿级日活/月活/连续签到统计。

Java 中用 Redis Bitmap 实现用户签到和活跃状态统计,核心是把用户每日行为映射为一个位(bit),用 SETBIT、GETBIT、BITCOUNT 和 BITOP 等命令操作,配合合理的 key 设计,就能在极低内存下完成亿级用户的日活/月活/连续签到等统计。
设计签到 key:按用户+时间维度组织
Bitmap 本质是字符串,每个字符 8 bit,所以一个长度为 N 的字符串最多存 N×8 个位。合理设计 key 是高效前提:
- 签到记录用
"sign:uid:{userId}:yyyyMM",比如"sign:uid:123:202406"表示用户 123 在 2024 年 6 月的签到位图 - 每天对应一个 bit 位:第 1 天 → offset=0,第 15 天 → offset=14,第 30 天 → offset=29
- 这样每月最多 31 个 bit,一个 key 只占约 4 字节(31/8 向上取整),非常节省空间
实现签到与查询:用 SETBIT 和 GETBIT
用户今天签到,只需设置对应 offset 为 1;查是否已签到,读对应位即可:
- 签到(假设今天是 6 月 18 日,即当月第 18 天 → offset=17):
jedis.setbit("sign:uid:123:202406", 17, true); - 查是否签到:
Boolean isSigned = jedis.getbit("sign:uid:123:202406", 17); - 注意:Jedis 的
setbit第三个参数支持true/false或"1"/"0",推荐用布尔值更直观
统计活跃用户:BITCOUNT + 时间范围聚合
要算某天有多少人签到,不能遍历所有用户——而是反向建“日期维度”位图(可选),但更常用的是按月扫描用户位图:
- 单用户当月签到天数:
Long days = jedis.bitcount("sign:uid:123:202406"); - 全量用户月活(需结合业务数据源):通常用 Redis Pipeline 批量读多个用户的
bitcount,再在应用层累加 - 若需“6 月 1 日到 6 月 5 日都签到的用户”,可用
BITOP AND合并多日位图(需先为每天单独建位图 key,如"sign:day:20240601")
判断连续签到:位运算 + offset 计算
连续签到 n 天,本质是检查最近 n 个 bit 是否全为 1。Redis 没有原生“连续 1”的指令,但可巧妙处理:
- 获取最近 n 天的位区间(例如查连续 7 天,取 offset [d-6, d] 共 7 位)
- 用
GETRANGE获取对应字节范围(注意字节对齐),再在 Java 中解析 bit 并校验是否全 1 - 更轻量做法:维护一个“最后签到日”字段(String 类型),配合签到逻辑判断间隔 —— 对大多数场景足够且更快
- 高阶技巧:用
BITPOS key 0 0 -1找从末尾起第一个 0 的位置,反推连续 1 长度(需保证位图右侧对齐签到日期)
不复杂但容易忽略:Bitmap 虽省空间,但 key 过多会增加 Redis 内存碎片;建议按月分片 + 定期过期(如设置 1 年 TTL),并用 SCAN 配合模式匹配做冷数据归档。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











