常用限流处理的几种方式:
1.通过限制单位时间段内调用量来限流
2.通过限制系统的并发调用程度来限流
3.使用漏桶(Leaky Bucket)算法来进行限流
4.使用令牌桶(Token Bucket)算法来进行限流
1通过限制单位时间段内调用量来限流:
通过限制某个服务的单位时间内的调用量来进行限流。从字面上,确实很容易理解,我们需要做的就是通过一个计数器统计单位时间段某个服务的访问量,如果超过了我们设定的阈值,则该单位时间段内则不允许继续访问、或者把接下来的请求放入队列中等待到下一个单位时间段继续访问。这里,计数器在需要在进入下一个单位时间段时先清零
对于限制单位时间段内调用量的这种限流方式,实现简单,适用于大多数场景,如果阈值可以通过服务端来动态配置,甚至可以当做业务开关来使用,但也有一定的局限性,因为我们的阈值是通过分析单位时间段内调用量来设置的,如果它在单位时间段的前几秒就被流量突刺消耗完了,将导致该时间段内剩余的时间内该服务“拒绝服务”,可以将这种现象称为“突刺消耗”
2通过限制系统的并发调用程度来限流:
通过严格限制某服务的并发访问程度,其实也就限制了该服务单位时间段内的访问量
并发的阈值设置成多少比较合适?比如限制服务的并发访问数是100,而服务处理的平均耗时是10毫秒,那么1分钟内,该服务平均能提供( 100 / 10 ) * 60 * 100 = 6,000 次
通过线上业务的监控数据来逐步对并发阈值进行调优,只要肯花时间,我们总能找到一个即能保证一定服务质量又能保证一定服务吞吐量的合理并发阈值
3通过漏桶算法来进行限流:
漏桶算法是网络中流量整形的常用算法之一,它有点像我们生活中用到的漏斗,液体倒进去以后,总是从下端的小口中以固定速率流出,漏桶算法也类似,不管突然流量有多大,漏桶都保证了流量的常速率输出
漏桶算法其实是悲观的,因为它严格限制了系统的吞吐量
4.令牌桶算法限流
令牌桶算法从某种程度上来说是漏桶算法的一种改进,漏桶算法能够强行限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许某种程度的突发调用
在令牌桶算法中,桶中会有一定数量的令牌,每次请求调用需要去桶中拿取一个令牌,拿到令牌后才有资格执行请求调用,否则只能等待能拿到足够的令牌数
令牌桶算法的精髓就在于“拿令牌”和“放令牌”的方式
我们的做法
技术实现目的 : 单位时间内控制一定数量的用户进入活动页面
实现原理 : 使用漏桶算法,每次用户进去活动页面时,检查限流缓存计数值是否存在,如果存在,允许进入,并且计数递减一位;
当计数器归零后,表示该单位时间内可参与人数已满,后续用户进入排队系统。
排队静态页面按照固定秒数时间后,自动会跳到限流控制页面,重新查询缓存计数值
注意:
1、排队页面纯HTML处理,可以容纳更多的请求数
2、容错页面做成和排队页面差不多的纯静态脚本,让用户无感知
3、后台需要设置合理的单位时间并发数限制
硬货来啦:
$redis = getRedis(); // 获取自己的redis资源
//整理正确的缓存键名,带有时间(测试时,定位到分钟,实际使用时,可以限制到秒)
$cacheKey = $config['自己的cacheKey'].'_'. date('Y-m-d-H:i:s', time());
//如果不存在缓存,计数器初始化
if(!$redis->exists($cacheKey)){
$redis->set($cacheKey, 预置限流阈值);
$redis->expire($cacheKey, 100);//100秒后销毁缓存
}
$counts = (int)$redis->get($cacheKey);
if($counts <= 0){
//当计数器统计数小于等于0时,用户进入排队系统
header('HTTP/1.1 404 Not Found');
$redirect_url = 自己的静态页;
}else{
//可以进入活动
$redirect_url = 自己的活动页;
//计数递减
if($counts > 0){
$redis->decr($cacheKey);
}
}
header("location:$redirect_url");