Redis Bitmap 签到与 UV 统计

当数据能表达为“某位置是否发生过”时,位图可以用很少的空间保存大量布尔状态。用户每日是否签到、活动是否参与过,都可以映射成某个 bit。独立访客 UV 则是另一类问题:需要对大量用户去重,适合考虑 HyperLogLog 这类近似计数结构。

1. 用 Bitmap 保存签到

一个常见设计是每个用户每月一张位图:键名包含用户和年月,日期偏移量对应某一天。比如把 1 号映射到 offset 0,31 号映射到 offset 30。

1
2
3
4
SETBIT sign:{userId}:2026-10 0 1   # 10 月 1 日签到
SETBIT sign:{userId}:2026-10 5 1 # 10 月 6 日签到
GETBIT sign:{userId}:2026-10 5 # 查询 10 月 6 日是否签到
BITCOUNT sign:{userId}:2026-10 # 统计本月签到次数

按月拆键能让键的语义和生命周期更清晰。写代码时要处理月份长度、时区和日期边界;签到规则如果允许补签,还要单独定义可修改范围。

2. 连续签到天数

把当月位图按日期读取后,从今天或昨天开始向前检查连续的 1,即可计算连续签到天数。若用 BITFIELD 一次读取多个位,注意位偏移方向和字节序;初学时可以先读取后在应用中按明确的日期顺序计算,并用跨月例子验证。

3. UV 与 HyperLogLog

精确统计某段时间内的唯一用户,可以用集合保存用户标识并查询集合基数,但内存随用户数量增长。HyperLogLog 使用概率算法估算基数,内存开销较小,但结果有误差,适合总体 UV 估算,不适合需要精确名单或逐个判断用户是否访问过的场景。

每日统计可以按日期设置键,例如 stats:uv:2026-10-17,把经过业务定义的匿名访客标识加入 HyperLogLog,再读取估算基数。标识应避免直接存储可识别个人的信息;跨日合并和隐私保留策略也要按业务需要设计。

4. 选择结构前先问的问题

需求 合适的思路
判断某用户某天是否签到 Bitmap
统计某用户当月签到次数 Bitmap 的位统计
精确列出签到用户 Set 或数据库记录
估算大量访客的去重总数 HyperLogLog
精确判断某用户是否访问过 Set、数据库或其他精确索引

5. 小结

Bitmap 适合把离散事件映射到紧凑的位序列;HyperLogLog 适合低内存的近似去重计数。两者解决的问题不同,不能因为都“省空间”就互相替代。