Redis Bitmaps如何实现用户签到功能的查询?

P粉602998670

P粉602998670

2026-07-23

329人浏览

原创

用 getbit 可查单日签到状态:key 为 sign:yyyymm:uid,offset 为当月第几天减1,返回1表示已签、0表示未签;错误做法是用时间戳或超31的 offset,会导致内存浪费。

redis bitmaps如何实现用户签到功能的查询?

查用户某天是否签到,直接用 GETBIT;查当月签到天数,用 BITCOUNT;但查“当前连续签到天数”不能靠单条命令,得组合逻辑或额外结构。

怎么用 GETBIT 查单日签到状态?

这是最轻量、最常用的查询方式,O(1) 时间,无误判风险。

  • key 必须和写入时一致,比如 sign:202607:1001(年月+用户ID),offset 是「当月第几天减 1」:7 月 14 日 → offset = 13
  • 执行 GETBIT sign:202607:1001 13,返回 1 表示已签,0 表示未签,key 不存在时也返回 0
  • 常见错误:把时间戳当 offset(如 1720890900),导致位图稀疏、内存暴涨;或 offset 超出 31(7 月最多 31 天),高位全 0 但分配了大量空字节

怎么用 BITCOUNT 统计当月签到总天数?

适合做月度汇总、排行榜基础数据,注意它统计的是整个 key 的 bit 1 个数,不是按日期范围。

Redis 8.2.3
Redis 8.2.3

Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。

下载
  • 如果 key 是按月设计的(如 sign:202607:1001),直接 BITCOUNT sign:202607:1001 即可得到该用户 7 月签到天数
  • 若 key 是跨月或按天聚合的(如 sign:20260701 存全站当日签到),则需配合 [start end] 参数截取字节范围——但注意:单位是字节,不是位,换算麻烦且易错
  • 性能提示:BITCOUNT 时间复杂度是 O(N),N 是底层字符串字节数。一个 31 位的 bitmap 实际只占 4 字节,很快;但若因 offset 错误导致分配了 1MB 空间,哪怕只设 1 个 bit,也会慢几毫秒

为什么 BITPOS 不能直接算连续签到天数?

BITPOS 只能找「第一个」0 或 1,而连续签到需要从最新签到日往前扫描最长连续 1 序列——这在 Redis 原生命令里没有等价操作。

  • 比如用户 7 月 1–3、12–14 都签到了,BITPOS sign:202607:1001 0 -1(从末尾往前找第一个 0)会返回 offset=10(即 7 月 11 日),但这只是断点,不是连续长度
  • 想算「当前连续多少天」,必须知道最近一次签到是哪天(比如 7 月 14 日),再逐位往前检查:13→12→11…直到遇到 0。纯靠客户端循环 GETBIT 最坏 O(31),高并发下不可接受
  • 工程解法通常是:写入时同步维护一个额外字段(如 user:1001:streak),用 Lua 脚本保证原子性;或用 BITFIELD + BITFIELD_RO 批量读取一段位,减少 RTT

查历史月份签到情况,key 设计和存储策略最关键

Redis 不适合长期存所有历史数据,否则内存不可控,查旧数据也慢。

  • 推荐方案:只把「当前月」bitmap 放 Redis,历史月数据落库(MySQL/ClickHouse)。查历史时走 DB,查当月走 Redis —— 启动时自动预热当前月 key
  • key 命名别用 sign:user_id:yyyyMM 这种,容易和其它 string 混淆;统一用 sign:yyyyMM:user_id,便于运维识别和 scan 过滤
  • 如果真要查跨月连续性(比如 6 月 30 日 → 7 月 1 日),不能靠两个 key 拼接计算:6 月 key 里 offset=29 是 6 月 30 日,7 月 key 里 offset=0 是 7 月 1 日,但这两个 key 之间无关联,得业务层判断日期是否连续并分别查

真正难的不是查单日或总数,而是「连续天数」这种带状态依赖的查询——它逼你做权衡:要么加额外字段维护状态,要么接受客户端多轮请求,要么引入异步校验兜底。Bitmap 本身只管存和取,连续性是业务逻辑,不是位运算能一键解决的。

相关专题

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

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

2025.09.05

130

5

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

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

2025.11.16

223

7

golang map原理
golang map原理

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

2025.11.17

350

20

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

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

2025.11.27

139

6

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

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

2023.11.02

1907

19

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

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

2023.11.14

1579

11

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

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

2024.04.02

2524

6

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

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

2024.04.07

518

6

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

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

2024.04.07

525

6

热门下载

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

精品课程

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

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 9万人学习