下面我们通过使用redis实现一个简单通用的令牌桶限流算法

1679369891

解决问题

 令牌桶算法主要是以桶的容量为基准,以固定的时间来生产令牌,有效的解决了漏桶效率不高的问题

具体实现

  • 创建redis对象并定义缓存
$redis = $this->connect();
$key = "aaaaa";
  • 开启 watch 并定义定义每分钟最大请求数量
$current_time = time();
$max_count = 320;
$total_s   = 60;
$redis->watch($key);
  • 计算平均值用于限制每秒请求数量
$rate = (int)(($max_count / $total_s) * ($current_time - ¥result_array["time"]));
  • 取出最大容量与桶内容量最小值
$num = min($max_count, ($result_array["num"] + $rate));
  • 判断令牌数
/* 令牌小于0 */
if ($num <= 0) {
    return false;
}
  • 重新保存令牌
$result = json_encode(["num" => $num - 1, "time" => $current_time]);

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

完整代码

$redis = $this->connect();
$key = "aaaaa";

$current_time = time();
$max_count = 320;
$total_s   = 60;

$redis->watch($key);


$result = $redis->get($key);
if ($result) {

    $result_array = json_decode($result, true);

    /* 计算生产速率 */
    $rate = (int)(($max_count / $total_s) * ($current_time - $result_array["time"]));

    /* 取出最大容量与桶内容量最小值 */
    $num = min($max_count, ($result_array["num"] + $rate));

    /* 令牌小于0 */
    if ($num <= 0) {
        return false;
    }

} else {
    /* 若不存在则创建通容量 */
    $num = $max_count;
}

$result = json_encode(["num" => $num - 1, "time" => $current_time]);

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

return true;

 通过以上代码我们令牌桶限流算法,有兴趣的同学可以尝试一下