如何利用Redis实现短视频的点赞与踩功能_通过Set或Bitmaps存储

阿静吖_4009

阿静吖_4009

2026-06-02

714人浏览

原创

短视频点赞场景下,set 更稳妥;bitmap 虽省内存但必须将用户 id 重映射为紧凑逻辑 id,否则因 offset 过大导致内存爆炸,且无法反查用户、不支持原子互斥操作。

如何利用redis实现短视频的点赞与踩功能_通过set或bitmaps存储

直接说结论:短视频场景下,Set 更稳妥,Bitmap 有明显收益但必须严控 offset 范围,否则极易因用户 ID 稀疏或错配导致内存爆炸。

为什么短视频点赞不能无脑用 Bitmap

Bitmap 的 offset 是按用户 ID 当作数组下标用的。如果系统里用户 ID 是自增主键,且从 1 开始、连续、不跳号,那 SETBIT video:123 456789 1 是安全的;但现实中短视频平台的用户 ID 往往是雪花算法生成(如 1298473029485720394),直接当 offset 会导致 Redis 分配数百 MB 甚至 GB 内存——这不是“省空间”,是制造事故。

真实踩坑案例:某平台误将商户 ID(起始值设为 21 亿)作为 offset,单个 SETBIT 就触发 Redis 分配约 250MB 内存,集群迅速 OOM。

  • offset 超过 1000 万时,内存占用 ≈ offset / 8 / 1024 / 1024 MB,不是线性增长,是按最大下标向上取整分配整块内存
  • 无法用 GETBIT 判断“某个大 ID 是否存在”,只能确认“该偏移位是否为 1”,但中间大量 0 位已占满内存
  • 不支持反查:“查出所有给视频 123 点过赞的用户”这种需求,Bitmap 完全做不到

Set 实现点赞/踩的最小可行结构

用两个独立 key 分离点赞和点踩,避免逻辑耦合:

  • 点赞集合:like:video:123
  • 点踩集合:dislike:video:123

关键操作全部基于原生命令,不依赖业务层判断状态:

Redis Skill - 高性能缓存管理
Redis Skill - 高性能缓存管理

Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。

下载
  • 用户点赞:SADD like:video:123 456789(重复执行无副作用)
  • 用户点踩:SADD dislike:video:123 456789
  • 取消点赞:SREM like:video:123 456789
  • 检查是否点赞:SISMEMBER like:video:123 456789 → 返回 1 或 0
  • 互斥校验(点赞后不能点踩)需业务层控制,Redis 不自动拦截

总点赞数用 SCARD like:video:123,毫秒级返回;点踩数同理。无需额外计数器,也无需担心并发写覆盖。

Bitmap 可用但必须重映射 offset

真要用 Bitmap 节省内存,唯一安全路径是把原始用户 ID 映射成紧凑、连续、可控的整数 ID(即“逻辑 ID”),再作为 offset:

  • 映射方式必须是确定性单向函数,例如 user_id % 10000000 不行(冲突高),推荐用布隆过滤器 + 自增序列或预分配 ID 池
  • 映射表本身要持久化(MySQL 或 Redis Hash),且保证原子性:先查映射、再 SETBIT、失败则回滚映射申请
  • BITCOUNT video:123 只能统计总点赞数,无法区分“谁点了”,所以必须搭配另一个结构(如 Set 或 Hash)存用户行为快照用于审计或召回
  • 上线前必须压测:模拟最高用户 ID 对应的 offset,验证 Redis 内存分配与响应延迟

别忽略的细节:点赞/踩状态同步与一致性

前端双态按钮(赞/踩)切换时,后端不能只依赖 Redis 返回结果做 UI 更新——SISMEMBER 和 SCARD 是两个命令,中间可能有其他用户操作,造成视觉错乱。

更可靠的做法是:一次请求完成状态判定 + 增删动作 + 总数读取,用 Lua 脚本封装:

eval "local liked = redis.call('sismember', KEYS[1], ARGV[1]) local disliked = redis.call('sismember', KEYS[2], ARGV[1]) if liked == 1 then redis.call('srem', KEYS[1], ARGV[1]) elseif disliked == 0 then redis.call('sadd', KEYS[1], ARGV[1]) end return {redis.call('scard', KEYS[1]), redis.call('scard', KEYS[2])}" 2 like:video:123 dislike:video:123 456789

这样点赞/点踩互斥、总数准确、网络往返仅 1 次。而 Bitmap 方案目前没有等效的原子多操作支持,必须靠客户端协调,风险更高。

相关专题

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

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

2025.09.05

490

5

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

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

2025.11.16

323

7

golang map原理
golang map原理

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

2025.11.17

513

20

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

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

2025.11.27

263

6

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

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

2023.11.02

4309

19

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

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

2023.11.14

3815

11

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

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

2024.04.02

6952

6

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

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

2024.04.07

623

6

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

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

2024.04.07

736

6

热门下载

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

精品课程

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

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习