在短信平台中,滑动时间窗算法主要用于实时监控每个时间段内的消息流量,并在超出预设阈值时立即进行拦截。
一、算法原理
-
滑动时间窗的概念:
维护一个固定时长的时间窗口(如1秒、5秒或更长),在窗口内统计进入系统的短信数量。与固定时间窗不同,滑动窗口能够实时更新,避免了窗口边界效应,从而更加平滑地控制流量。 -
异常流量拦截:
当前窗口内的短信数量超过预设的安全阈值时(例如每秒允许的最大消息数),系统立即触发拦截逻辑,拒绝或延迟处理后续请求,以保证系统的稳定性和资源的合理分配。
二、实现步骤
-
记录时间戳:
每条短信到达时,将其时间戳记录在一个数据结构中(例如队列或滑动窗口计数器)。 -
维护滑动窗口:
对于每个新的请求,在记录其到达时间后,遍历队列移除掉窗口范围外的旧时间戳。例如,假设时间窗口设定为1秒,当前时间为T
,则清除所有早于T - 1秒
的记录。 -
计数与判断:
计算窗口内剩余记录的数量。如果数量超过预设的阈值,则认为流量异常,直接拦截当前请求或进行限流处理。 -
反馈与降级:
一旦检测到异常流量,可以将该请求记录下来(用于统计和报警),并返回错误或提示信息给上游系统,确保不会对短信平台核心功能造成影响。
三、 代码示例
1.Java实现
// 定义一个线程安全的队列来存储消息的时间戳
ConcurrentLinkedQueue<Long> timestampQueue = new ConcurrentLinkedQueue<>();
// 设定时间窗口大小(毫秒)和阈值
long windowSize = 1000; // 1秒
int threshold = 10000; // 例如每秒最多处理10,000条短信
public boolean allowRequest() {
long now = System.currentTimeMillis();
// 清除时间窗口外的旧数据
while (!timestampQueue.isEmpty() && (now - timestampQueue.peek()) > windowSize) {
timestampQueue.poll();
}
// 判断当前窗口内的请求数是否超过阈值
if (timestampQueue.size() >= threshold) {
// 超过阈值,拒绝或延迟处理
return false;
}
// 记录当前请求的时间戳并允许处理
timestampQueue.add(now);
return true;
}
在这个示例中,每次收到短信请求时都会调用allowRequest()
方法。若当前窗口内的请求数达到或超过阈值,则返回false
,实现100%的异常流量拦截;否则,将当前请求记录进去,允许继续处理。
2.Redis分布式实现
使用Redis Sorted Set(ZSET)存储请求时间戳,通过ZREMRANGEBYSCORE
清理过期数据,ZCARD
统计当前数量。
-- KEYS[1]: 限流key(如user:123)
-- ARGV[1]: 窗口时间(毫秒)
-- ARGV[2]: 最大请求数
local key = KEYS[1]
local now = tonumber(redis.call('TIME')[1])
local window = tonumber(ARGV[1]) / 1000
local max = tonumber(ARGV[2])
-- 移除时间窗口外的记录
redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local current = redis.call('ZCARD', key)
if current >= max then
return 0
else
redis.call('ZADD', key, now, now)
redis.call('EXPIRE', key, window)
return 1
end
四、动态流量控制与扩展
-
动态调整阈值:
根据历史数据和系统负载情况,可以动态调整阈值,使得系统在高峰期和低峰期均能保持稳定。 -
多级处理:
除了全局流量控制外,还可以针对不同机构或通道进行细粒度控制,确保各业务线均不受单一异常流量影响。 -
配合监控报警:
实时监控当前窗口内的请求数及拦截率,一旦检测到异常流量趋势,可触发报警,辅助运维人员及时干预。
五、滑动时间窗算法与Sentinel限流的关系与区别
1.滑动时间窗
-
用途:主要用于控制瞬时流量(例如在一秒或几秒内的请求数),确保在高并发时,系统不会因为短时间内大量请求导致过载。它通过实时监控请求数,滑动更新时间窗口,做到高精度流量控制。
-
应用场景:用于短信发送的细粒度控制:你可以为每个短信渠道、用户或接口设置一个动态流量控制机制,实时限制每秒或每分钟可以发送的短信数量,防止某个用户或接口在短时间内发送过多短信,造成系统负担。比如说:单个用户每秒发送短信≤500条,拦截恶意高频请求(业务规则);
2.Sentinel
-
用途:Sentinel 是一个分布式系统的流量控制框架,它可以基于 QPS(每秒请求数)、并发线程数等指标进行流量控制。Sentinel 提供了 资源级别的限流,并支持多种规则(如链路限流、系统负载限流等)。
-
应用场景:用于全局限流与流量调度,更适合在服务级别进行流量控制,如控制 API 调用、请求量过大时的流量削峰等。可以用来保护整体的短信平台,控制系统的整体流量,防止因短期内大量的请求(无论来自哪个渠道)影响平台的可用性。例如,当流量过载时,Sentinel 可根据规则触发熔断、降级,减少请求处理压力。比如说:限制短信接口整体QPS≤10万,防止下游运营商通道过载(系统保护)。
维度 | 滑动时间窗算法 | Sentinel限流策略 |
---|---|---|
应用层级 | 业务层(如短信发送频率控制) | 系统层(如接口全局QPS保护) |
控制粒度 | 细粒度(用户、IP、内容维度) | 粗粒度(服务、接口维度) |
实现方式 | 自定义逻辑(如Redis Lua脚本) | 开箱即用(配置规则+动态治理) |
核心目标 | 精准识别业务异常(如薅羊毛、刷单) 聚焦业务逻辑的合规性(防滥用); | 聚焦系统稳定性(防崩溃), 防止系统过载(如熔断、降级) |
3. 冲突规避原则
-
分层设计:
滑动时间窗作用于业务逻辑层(如发送前校验),Sentinel作用于网关层或RPC框架层(如Spring Cloud Alibaba集成)。 -
阈值协调:
Sentinel的全局QPS阈值需大于滑动时间窗各维度阈值之和,避免规则互相压制。