当前位置:首页 > PHP

php实现令牌桶

2026-02-16 01:44:50PHP

令牌桶算法简介

令牌桶算法是一种常用的流量控制算法,用于限制请求速率。核心思想是系统以固定速率向桶中添加令牌,请求处理需要消耗令牌,桶空时拒绝请求。

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实现:

php实现令牌桶

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脚本保证原子性 可结合漏桶算法实现更平滑的流量控制

标签: 令牌php
分享给朋友:

相关文章

php实现购物车

php实现购物车

PHP实现购物车功能 购物车功能是电商网站的核心模块之一,通常涉及商品添加、删除、数量修改和结算等操作。以下是使用PHP实现购物车功能的几种方法。 使用Session存储购物车数据 Session是…

php实现表单

php实现表单

PHP 表单基础实现 创建一个简单的 PHP 表单需要 HTML 表单结构和 PHP 处理脚本。以下是一个完整的示例: HTML 表单部分 (form.html) <form action=…

php实现mysql

php实现mysql

PHP 连接 MySQL 的基本方法 PHP 提供了多种方式与 MySQL 数据库进行交互,以下是最常用的几种方法。 使用 MySQLi 扩展 MySQLi 是 MySQL 的改进扩展,支持面向对…

php实现接口

php实现接口

PHP 实现接口的方法 在 PHP 中,接口(Interface)用于定义一组方法的规范,而不实现具体功能。类可以实现一个或多个接口,并必须实现接口中定义的所有方法。 定义接口 接口使用 inter…

php 实现类

php 实现类

PHP 类的基本实现 在 PHP 中,类通过 class 关键字定义,后跟类名和一对花括号。类名通常遵循大驼峰命名法(如 ClassName)。以下是基本语法: class ClassName {…

php 实现队列

php 实现队列

PHP 实现队列的方法 PHP 可以通过多种方式实现队列功能,以下是几种常见的实现方法: 使用数组实现队列 PHP 数组可以通过 array_push 和 array_shift 函数模拟队列的先进…