欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

带流量限制器的令牌桶算法的 php 实现

最编程 2024-03-07 12:44:42
...

先上代码

<?php
function requestLimit(int $uid=1, int $limitNum=6, int $expire=60)
{
    $key = 'limit_user_'. $uid;
    $nowtime  = time();

    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);

    $redis->watch($key);

    $limitVal = $redis->get($key);
    if ($limitVal) {
        $limitVal = json_decode($limitVal, true);
        $num   = min($limitNum, ($limitVal['num']) + (int)(($limitNum / $expire) * ($nowtime - $limitVal['time'])));
        if ($num <= 0) {
            return false;
        } 
    } else {
        $num = $limitNum;
    }
    $redisVal = json_encode(['num' => $num-1, 'time' => $nowtime]);

    $redis->multi();
    $redis->set($key, $redisVal);
    $redis->expire($key, $expire);
    $robResult = $redis->exec();
    if (!$robResult) {
        return false;
    }

    return true;
}
var_dump(requestLimit());

一 、场景描述

在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制。比如对于某个 用户,他在一个时间段(interval)内,比如 1 分钟,调用服务器接口的次数不能够 大于一个上限(limit),比如说 100 次。如果用户调用接口的次数超过上限的话,就直接拒绝用户的请求,返回错误信息。
服务接口的流量控制策略:分流、降级、限流等。本文讨论下限流策略,虽然降低了服务接口的访问频率和并发量,却换取服务接口和业务应用系统的高可用。

二、常用的限流算法

1、漏桶算法
漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:

image

可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。
因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率.因此,漏桶算法对于存在突发特性的流量来说缺乏效率.

2、令牌桶算法
令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

image

令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.

参考文章:https://www.jianshu.com/p/9f76dd2757c7