Redis怎么精准限制特定IP访问,防止乱进乱用,控制权限的那些事儿
- 问答
- 2026-01-02 05:24:58
- 4
主要整合自网络技术社区如CSDN、博客园以及Redis官方文档中关于限流和权限控制的常见实践思路)
要使用Redis来精准限制特定IP的访问,防止其乱进乱用,核心思路是利用Redis速度快、支持过期时间和原子操作的特点,来实时计数和判断,这就像给每个IP地址发一个“通行证”,并严格规定它在特定时间内的使用次数。
最基本的招数:固定窗口计数器
这是最简单直接的方法,想象一下,我们把时间切成一个个一分钟的窗口,对于每一个IP,我们都在Redis里给它设置一个键值对,key可以是 limit:ip:[具体的IP地址],value就是这个IP在这一分钟里访问了多少次。
具体操作是:
- 每当一个IP发起请求时,我们首先用
INCR命令给它的计数器加1。INCR这个命令是原子性的,意味着即使很多请求同时来,Redis也会一个一个处理加1,不会出现计数错误。 - 加1之后,我们同时检查这个计数器的值,如果是1(也就是第一次访问),我们立刻用
EXPIRE命令给这个key设置一个60秒的过期时间,这样一分钟过后,这个计数就自动清零了,下一个分钟重新开始。 - 如果检查发现计数器的值已经超过了我们设定的门槛(比如60次),那就立刻拒绝这个请求,返回“访问过于频繁”之类的提示。
(来源:Redis官方命令文档中对INCR和EXPIRE的说明,以及大量入门级限流教程) 这个方法的好处是简单易懂,Redis的操作很少,性能消耗低,但它有个明显的缺点:不够平滑,比如在上一分钟的最后一秒和下一分钟的第一秒,这个IP可以连续发起120次请求,虽然每个窗口都没超限,但在这两秒内其实造成了密集攻击,这就好比一个水龙头,虽然一小时只放一吨水,但它可能在一分钟内就全放完了。
更平滑的招数:滑动窗口
为了解决固定窗口在边界时间点的爆发问题,我们可以想办法让窗口“滑动”起来,这里一个常见的做法是使用有序集合(Sorted Set)。
我们为每个IP创建一个有序集合,集合的key可以设计为 sliding_window:ip:[具体的IP地址],集合里的每个成员(member)是每次请求的时间戳(比如精确到毫秒),而分值(score)也是这个时间戳。
操作步骤是:
- 当请求到来时,首先用
ZREMRANGEBYSCORE命令,删除这个集合中所有时间戳在当前时间窗口之前(比如当前时间减去10000毫秒)的成员,这一步相当于把窗口之外的老旧请求记录清理掉,只保留最近10秒内的。 - 用
ZCARD命令计算当前集合中还剩多少个成员,这个数字就是当前IP在最近10秒内的请求数。 - 如果这个数量已经超过限制(比如30次),就拒绝请求。
- 如果还没超限,就把当前这次请求的时间戳作为成员和分值,用
ZADD命令添加到有序集合里。 - 为了让集合不会无限膨胀,我们每次可以顺便用
EXPIRE命令给整个集合设置一个略大于窗口时间的过期时间(比如15秒),做一次清理保障。
(来源:多位技术博主如“程序员小灰”等在讲解分布式限流时频繁引用的方案) 这个方法比固定窗口精准得多,能有效防止边界攻击,但代价是每次请求需要执行多个Redis命令(删除、计数、添加),对Redis的资源消耗会大一些。
应对突发流量:令牌桶算法
有时候我们不想一刀切地限制死,而是希望IP在空闲时能积攒一些“额度”,应对合理的突发请求,这就要用到令牌桶算法,Redis同样可以实现。
思路是:
- 我们为每个IP设置一个键,用来存储当前桶里的“令牌”数量,key 是
token_bucket:ip:[IP地址]。 - 我们需要另一个键或者借助Lua脚本,来记录最后一次补充令牌的时间。
- 每当请求到来时,我们先计算从上一次到现在,应该往桶里添加多少新令牌(比如每秒加10个,但不能超过桶的容量)。
- 检查桶里的令牌数,只要令牌数大于等于1,就允许请求通过,并从桶中扣除一个令牌,如果令牌数为0,则拒绝请求。
(来源:维基百科“令牌桶算法”词条原理,结合Redis的INCRBY和GETSET等命令的实现讨论) 这个算法非常灵活,既能限制平均速率,又允许一定程度的突发流量,是很多API网关采用的限流方式,在Redis中实现它通常需要组合多个命令,为了保证原子性,最好使用Lua脚本。
控制权限:IP黑白名单
除了限流,直接控制权限也是防止乱进乱用的关键,用Redis实现黑白名单非常简单高效。
- 黑名单:把恶意IP、爬虫IP等放进一个Redis集合(Set)里,key比如叫
ip_blacklist,每次请求来时,用SISMEMBER命令检查一下这个IP在不在集合里,在的话就直接拒绝,可以给黑名单的key设置一个过期时间,实现临时封禁,或者不设置过期时间实现永久封禁。 - 白名单:同理,创建一个
ip_whitelist集合,只允许集合内的IP访问,这在内部系统或API开放给特定合作伙伴时非常有用,检查方式同样是用SISMEMBER。
(来源:这是Redis集合数据类型最典型的应用场景之一,常见于安全防护的基础讨论) 因为Redis的Set查询效率非常高,所以用这种方式做权限校验速度极快,对业务性能影响很小。
重要提醒:
无论用哪种方法,有几点需要特别注意:
- 原子性:像“检查-计数-设置过期时间”这样的组合操作,在高并发下必须保证原子性,否则会出问题,最可靠的方法是使用Redis的Lua脚本,它能确保一系列命令被连续执行,中间不会被其他命令打断。
- 内存考虑:如果面对的IP数量极其庞大(比如全网攻击),无差别地为每个IP都记录详细窗口信息可能会占用大量内存,这时可能需要考虑分层限流(先粗粒度后细粒度),或者对长时间不活跃的KEY进行清理。
- 策略组合:在实际应用中,通常不会只使用一种策略,可能是“白名单+黑名单+滑动窗口限流”组合使用,为不同优先级的IP设置不同的限流阈值,从而实现精准而灵活的控制。
Redis凭借其高性能和丰富的数据结构,为我们提供了多种强大的工具来精准管理IP访问,关键在于根据实际业务场景的安全性和性能要求,选择合适的算法和数据结构,并注意实现的细节。

本文由太叔访天于2026-01-02发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/72891.html
