用户触达限流

简介:

采用令牌桶方式对短信发送进行分布式限流

业务背景:

触达平台通过短信触达用户的场景日均推送量500万条,高峰时触达会达1000万+,超过了短信系统性能,短信系统需要对模块设置上限,超过上限会被丢弃。短信系统初步评估改造成本大,需触达系统管控推送速率,限制接口请求为QPS200(1s内同时请求的手机号码数)。

首先对触达项目短信场景做初步了解:

由此图可看到,短信推送是触达项目的一个中间环节,如果只是对短信接口进行限流,会产生“瓶颈”效应,拖慢整个项目执行速率。当项目高峰时,会有更多的线程阻塞等待短

信执行,产生系统风险。

优势:

1 短信发送异步机制:为避免产生短信场景“瓶颈效应”,采用kafka将短信发送作为异步事件,逐步消费。

2 令牌桶限流: 令牌桶算法允许在限流值内的突发流量,因为它会积累令牌直到达到桶的容量。这意味着在短时间内可以处理超过平均速率的请求,而不是简单地按照固定的速率限制流量;

3 分布式环境下的一致性:RRateLimiter是基于Redis实现的,因此它可以在分布式系统中保持限流策略的一致性。无论是多个应用实例还是多个服务节点,都可以使用相同的限流规则。

建设方案:

一:限流算法的选择

  1. 固定窗口计数器算法(Fixed Window Counter)
    优点:实现简单,容易理解。
    缺点:可能会出现临界问题,即在窗口切换的瞬间,流量会翻倍,导致短时间内的流量超过阈值。
  2.  滑动窗口计数器算法(Sliding Window Counter)
    优点:相比滑动窗口日志算法,减少了存储和计算开销。
    缺点:实现相对复杂,需要维护多个时间窗口的计数器。
  3.  令牌桶算法(Token Bucket)
    优点:提供平滑的限流控制,允许一定程度的突发流量,灵活性高。
    缺点:如果配置不当,可能会导致短时间内的流量超过系统极限。
  4.  漏桶算法(Leaky Bucket)
    优点:输出流量非常平滑,无论输入流量如何变化。
    缺点:不允许突发流量,可能会导致系统处理能力未被充分利用。

二 实现步骤

1、短信发送异步化

原短信场景直接调用UNP批量短信发送接口发送短信。此处将批量短信发送内容封装为JSON消息串,通过kafka生产者将消息发送至topic。

2、创建RedissonRateLimiter限流器

使用RedissonClient客户端创建限流器:

RRateLimiter rateLimiter = this.redissonClient.getRateLimiter(rateLimiterName);

初始化限流器的同时就给限流器起了名字,及对象的行为,如myRateLimit,下面用到限流器名的地名军用myRateLimit代替

3、配置限流器

创建限流器后要对其进行配置,并将配置存到redis总,主要配置包括

RateType:限流器类型:OVERALL:分布式限流;PER_CLIENT:单例限流

rate:速率(时间窗口内产生令牌数量)

rateInterval: 窗口时长

RateIntervalUnit :时间单位,如毫秒

//将限流器配置设置到redis的hash中 参数依次为上述4个入参

redis.call('hsetnx', KEYS[1], 'rate', ARGV[1])
redis.call('hsetnx', KEYS[1], 'interval', ARGV[2])

return redis.call('hsetnx', KEYS[1], 'type', ARGV[3])

 4、申请令牌(LUA流程)

 

// 核心LUA

local currentValue = redis.call('get', valueName);

if currentValue ~= false then

if tonumber(currentValue) < tonumber(ARGV[1]) then

return redis.call('pttl', valueName);
else
redis.call('decrby', valueName, ARGV[1]);

return nil;

end;

else

redis.call('set', valueName, rate, 'px', interval); redis.call('decrby', valueName, ARGV[1]);

return nil;

首先尝试获取 valueName 对应的当前值。如果当前值存在(不为 false),脚本会检查这个值是否小于 ARGV[1](传入的参数,表示请求的数量)。如果小于,说明已经达到了限制,返回该键的剩余过期时间(使用 pttl 命令)。如果不小于,脚本将使用 decrby命令减少当前值,并返回 nil,表示请求可以继续。

如果当前值不存在,脚本将使用 set命令初始化这个键,设置其值为 rate,并设置过期时间为 interval(使用毫秒为单位)。然后,脚本将使用 decrby减少当前值,并返回 nil。

线上效果:

短信限流上线后,请求速率被均匀控制在200QPS(1s内同时请求的手机号码数)内。实现UNP系统方的要求。

下图为最近1小时内的消费情况,由于请求UNP是调用批量请求接口,每批次约10个手机号。APM采集为分钟级维度。可明显识别限流效果已生效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值