用户黑名单怎么用Redis搞定,性能和管理都方便不少
- 问答
- 2026-01-16 22:03:20
- 2
用户黑名单是很多系统都需要的基础功能,比如防止恶意用户刷帖、限制违规用户发言、拦截垃圾注册等,用传统的关系型数据库(比如MySQL)来做,虽然简单直接,但每次检查都需要去查数据库,当用户量巨大、请求非常频繁时(比如春运抢票、明星发微博后的评论场景),数据库很容易成为瓶颈,导致系统卡顿甚至崩溃。
Redis因为几个天生的优势,非常适合搞定黑名单场景,它的数据都放在内存里,读写速度极快,能达到微秒级别,这保证了检查黑名单这个高频操作不会拖慢整个系统,Redis提供了丰富的数据结构,让我们可以用最合适的方式来管理黑名单,既高效又灵活。

核心思路:用Redis的Set和Sorted Set
最常用的两种数据结构是Set(集合)和Sorted Set(有序集合),它们都能存储多个不重复的元素,非常适合用来存用户ID。

-
使用Set实现永久黑名单或需精确匹配的黑名单 Set的最大特点就是里面的元素是无序且唯一的,这正好符合黑名单的基本要求:一个用户要么在黑名单里,要么不在,不需要重复添加。
- 操作命令非常简单:
- 添加用户到黑名单:
SADD blacklist:user_id 123456(意思是向名为blacklist:user_id的集合里添加用户ID123456) - 检查用户是否在黑名单:
SISMEMBER blacklist:user_id 123456,Redis会直接返回1(存在)或0(不存在),这个操作的速度是常数时间的,非常快。 - 将用户移出黑名单:
SREM blacklist:user_id 123456 - 查看黑名单所有用户:
SMEMBERS blacklist:user_id(谨慎使用,如果黑名单很大,可能会影响性能,一般用于管理后台查看)
- 添加用户到黑名单:
- 适用场景:
- 永久封禁: 对于一些严重违规的用户,直接永久封禁,他们的ID就永远放在这个Set里。
- 需要精确匹配的场景: 比如黑名单是基于用户ID的,用Set非常合适。
- 操作命令非常简单:
-
使用Sorted Set实现带过期时间的黑名单 这是Redis解决黑名单问题的一个“杀手级”应用,Sorted Set除了存储成员(member),还会为每个成员关联一个分数(score),我们可以巧妙地把这个“分数”当成是用户黑名单的过期时间戳。

- 工作原理: 我们把要拉黑的用户ID作为成员(member),把他的解封时间点(比如当前时间戳 + 7天的秒数)作为分数(score)存入Sorted Set。
- 操作命令:
- 添加用户到黑名单(带7天过期时间):
ZADD blacklist:ttl 1717584000 123456(假设1717584000是7天后的一个具体时间戳) - 检查用户是否在有效黑名单内: 这个检查需要两步走,但依然高效。
- 先获取该用户的分数(即过期时间):
ZSCORE blacklist:ttl 123456 - 如果返回空(nil),说明不在黑名单,如果返回了一个时间戳,就拿这个时间戳和当前时间比较,如果时间戳大于当前时间,说明黑名单还在有效期内;如果小于当前时间,说明已经过期了。
- 先获取该用户的分数(即过期时间):
- 自动化清理过期黑名单: 这是Sorted Set最方便的地方,我们可以利用它根据分数范围排序的特性,定期执行一个任务:
ZREMRANGEBYSCORE blacklist:ttl 0 1717497600(这个命令会删除所有分数在0到1717497600(当前时间戳)之间的成员),因为过期的用户其分数(过期时间)肯定小于当前时间,这个命令一下,所有到期的用户就被自动清理出黑名单集合了,保证了集合不会无限膨胀,这个清理任务可以写个脚本每分钟跑一次,成本极低。
- 添加用户到黑名单(带7天过期时间):
- 适用场景:
- 临时封禁: 禁言7天”、“限制登录3天”等,这是最常见的需求。
实际应用中的管理和优化技巧
光有数据结构还不够,在实际项目中这样用会让管理和性能更好:
- 命名规范: 像上面的例子一样,给Key起个清晰的名字,
blacklist:user_id用于永久黑名单,blacklist:ttl用于临时黑名单,如果业务复杂,还可以加上前缀,如live_comment_blacklist:ttl(直播评论黑名单)。 - 封装检查逻辑: 不应该在业务代码里到处写Redis命令,应该统一封装一个服务或函数,比如叫
BlacklistService.checkUserStatus(userId),这个函数内部去处理是用Set还是Sorted Set,以及判断时间逻辑,这样以后想修改黑名单策略(比如从永久改为临时),只需要改这一个地方。 - 控制黑名单大小: 对于临时黑名单,一定要有上面提到的自动清理机制,对于永久黑名单,如果数据量真的巨大(上亿),可以考虑按用户ID的范围进行分片,存到多个Set里,
blacklist:shard_1,blacklist:shard_2,来分散单个Key的压力。 - 与数据库配合: 黑名单的源数据(谁、何时、为何被拉黑、解封时间)还是会存在MySQL这类数据库里,用于后台查询和审计,Redis只是作为一个超高速的缓存层,当管理员在后台操作拉黑时,程序应该同时向MySQL和Redis写入数据。
总结一下
用Redis做黑名单,核心就是利用其内存速度和高频数据结构。Set适合简单直接的封禁,Sorted Set通过将过期时间作为分数,完美解决了临时黑名单的自动管理问题。 这种方法相比直接查数据库,性能提升是数量级的,能让你的应用在高并发下依然稳定,通过简单的封装和定时任务,管理起来也非常方便,避免了手动清理的麻烦。
(参考文献:Redis官方文档中对Set和Sorted Set数据结构的说明;《Redis实战》一书中关于使用Redis实现社交网站功能的案例,其中提到了类似黑名单的实现思路。)
本文由邝冷亦于2026-01-16发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/82033.html
