php实现令牌桶
令牌桶算法简介
令牌桶算法是一种常用的流量控制算法,用于限制请求速率。核心思想是系统以固定速率向桶中添加令牌,请求处理需要消耗令牌,桶空时拒绝请求。
PHP实现令牌桶类
class TokenBucket {
private $capacity; // 桶容量
private $tokens; // 当前令牌数
private $lastTime; // 上次更新时间
private $rate; // 令牌生成速率(个/秒)
public function __construct($capacity, $rate) {
$this->capacity = $capacity;
$this->rate = $rate;
$this->tokens = $capacity;
$this->lastTime = time();
}
private function addTokens() {
$now = time();
$elapsed = $now - $this->lastTime;
$newTokens = $elapsed * $this->rate;
$this->tokens = min($this->capacity, $this->tokens + $newTokens);
$this->lastTime = $now;
}
public function consume($tokens = 1) {
$this->addTokens();
if ($this->tokens >= $tokens) {
$this->tokens -= $tokens;
return true;
}
return false;
}
}
使用示例
// 创建容量为10,速率1个/秒的令牌桶
$bucket = new TokenBucket(10, 1);
// 模拟请求处理
for ($i = 0; $i < 15; $i++) {
if ($bucket->consume()) {
echo "处理请求 $i\n";
} else {
echo "拒绝请求 $i (限流)\n";
}
sleep(1); // 模拟请求间隔
}
Redis实现分布式令牌桶
对于分布式系统,可使用Redis实现:
class RedisTokenBucket {
private $redis;
private $key;
private $capacity;
private $rate;
public function __construct($redis, $key, $capacity, $rate) {
$this->redis = $redis;
$this->key = $key;
$this->capacity = $capacity;
$this->rate = $rate;
}
public function consume($tokens = 1) {
$script = '
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local tokens = tonumber(ARGV[3])
local now = tonumber(ARGV[4])
local last = redis.call("hget", key, "last")
local current = redis.call("hget", key, "tokens") or capacity
if last then
local elapsed = now - last
current = math.min(capacity, current + elapsed * rate)
end
if current >= tokens then
current = current - tokens
redis.call("hmset", key, "tokens", current, "last", now)
return 1
end
return 0
';
return $this->redis->eval($script, [$this->key, $this->capacity, $this->rate, $tokens, time()], 1);
}
}
性能优化建议
使用时间窗口预生成令牌,避免每次请求都计算 对于高并发场景,建议使用Redis+Lua脚本保证原子性 可结合漏桶算法实现更平滑的流量控制







