本文目录导读:

我来为您提供PHP漏桶算法的实现代码:
基础漏桶算法实现
<?php
/**
* 漏桶算法实现
* 用于流量控制/限流
*/
class LeakyBucket {
private $capacity; // 桶的容量
private $leakRate; // 漏出速率(单位:请求/秒)
private $water; // 当前桶中的水量
private $lastLeakTime; // 上次漏水时间
/**
* @param int $capacity 桶容量(最大并发数)
* @param float $leakRate 漏水速率(每秒处理的请求数)
*/
public function __construct($capacity, $leakRate) {
$this->capacity = $capacity;
$this->leakRate = $leakRate;
$this->water = 0;
$this->lastLeakTime = microtime(true);
}
/**
* 尝试添加请求到桶中
* @return bool 是否允许通过
*/
public function allowRequest() {
$this->leak();
// 检查桶是否已满
if ($this->water < $this->capacity) {
$this->water++;
return true;
}
return false;
}
/**
* 漏水操作
*/
private function leak() {
$currentTime = microtime(true);
$elapsedTime = $currentTime - $this->lastLeakTime;
// 计算漏水量
$leakedAmount = $elapsedTime * $this->leakRate;
// 更新水量
$this->water = max(0, $this->water - $leakedAmount);
// 更新上次漏水时间
$this->lastLeakTime = $currentTime;
}
/**
* 获取当前桶中的水量
*/
public function getWater() {
$this->leak();
return $this->water;
}
/**
* 重置桶
*/
public function reset() {
$this->water = 0;
$this->lastLeakTime = microtime(true);
}
}
使用示例
<?php
// 示例:创建一个容量为10,每秒漏水5个的漏桶
$bucket = new LeakyBucket(10, 5);
// 模拟请求
$requests = 20; // 模拟20个请求
for ($i = 1; $i <= $requests; $i++) {
if ($bucket->allowRequest()) {
echo "请求 {$i}: 通过 ✓\n";
// 处理请求...
} else {
echo "请求 {$i}: 拒绝 ✗(限流)\n";
}
// 模拟请求间隔0.1秒
usleep(100000);
}
// 查看当前水量
echo "\n当前水量: " . $bucket->getWater() . "\n";
高级版本(支持Redis分布式限流)
<?php
/**
* Redis实现分布式漏桶算法
* 适用于多实例部署场景
*/
class RedisLeakyBucket {
private $redis;
private $key; // Redis key
private $capacity; // 桶容量
private $leakRate; // 漏水速率
/**
* @param Redis $redis Redis连接实例
* @param string $key 唯一标识
* @param int $capacity 桶容量
* @param float $leakRate 漏水速率
*/
public function __construct($redis, $key, $capacity, $leakRate) {
$this->redis = $redis;
$this->key = $key;
$this->capacity = $capacity;
$this->leakRate = $leakRate;
}
/**
* 尝试请求
* @return bool
*/
public function allowRequest() {
$luaScript = <<<LUA
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local leakRate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
-- 获取当前水量和时间
local water = tonumber(redis.call('get', key .. ':water') or '0')
local lastLeakTime = tonumber(redis.call('get', key .. ':time') or '0')
-- 如果还没有记录,初始化
if lastLeakTime == 0 then
lastLeakTime = now
end
-- 计算漏水量
local elapsedTime = now - lastLeakTime
local leakedAmount = elapsedTime * leakRate
water = math.max(0, water - leakedAmount)
-- 更新时间和水量
redis.call('set', key .. ':time', now)
-- 判断是否允许请求
if water < capacity then
water = water + 1
redis.call('set', key .. ':water', water)
return 1
else
redis.call('set', key .. ':water', water)
return 0
end
LUA;
$result = $this->redis->eval(
$luaScript,
[$this->key, $this->capacity, $this->leakRate, microtime(true)],
1
);
return $result == 1;
}
/**
* 重置限流器
*/
public function reset() {
$this->redis->del($this->key . ':water');
$this->redis->del($this->key . ':time');
}
}
使用示例(Redis版)
<?php
// Redis连接
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 创建分布式漏桶
$bucket = new RedisLeakyBucket($redis, 'api_limit', 10, 5);
// 测试请求
for ($i = 1; $i <= 20; $i++) {
if ($bucket->allowRequest()) {
echo "请求 {$i}: 通过 ✓\n";
} else {
echo "请求 {$i}: 拒绝 ✗\n";
}
usleep(100000);
}
使用场景建议
- API限流:控制接口调用频率
- 流量整形:平滑突发流量
- 资源保护:保护后端服务不被打垮
- 任务队列控制:控制任务处理速率
注意事项
- 参数调优:需要根据实际业务场景调整容量和漏水速率
- 性能考虑:Redis版本比内存版本稍慢,但支持分布式
- 精度问题:使用
microtime(true)保证时间精度 - 并发安全:Redis版通过Lua脚本保证原子性
这个漏桶算法实现适合大多数PHP项目的限流需求,您可以根据具体场景选择使用内存版本或Redis分布式版本。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播