当前位置:首页 > PHP

php实现 令牌桶

2026-02-15 06:20:14PHP

令牌桶算法简介

令牌桶算法是一种常用于流量控制和速率限制的算法。它维护一个固定容量的桶,按照固定速率向桶中添加令牌。请求需要获取令牌才能执行,若桶中没有足够令牌,请求会被限制。

PHP实现令牌桶

基于Redis的实现

使用Redis可以方便地实现分布式令牌桶,确保多服务器环境下的一致性。

class TokenBucket {
    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) {
        $now = microtime(true);
        $script = '
            local key = KEYS[1]
            local now = tonumber(ARGV[1])
            local capacity = tonumber(ARGV[2])
            local rate = tonumber(ARGV[3])
            local tokens = tonumber(ARGV[4])

            local lastTime = redis.call("hget", key, "time")
            local currentTokens = redis.call("hget", key, "tokens")

            if not lastTime then
                lastTime = now
                currentTokens = capacity
            else
                local elapsed = now - lastTime
                local newTokens = elapsed * rate
                currentTokens = math.min(capacity, currentTokens + newTokens)
                lastTime = now
            end

            if currentTokens >= tokens then
                currentTokens = currentTokens - tokens
                redis.call("hset", key, "time", lastTime)
                redis.call("hset", key, "tokens", currentTokens)
                return 1
            else
                return 0
            end
        ';

        return $this->redis->eval($script, [$this->key, $now, $this->capacity, $this->rate, $tokens], 1);
    }
}

// 使用示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$bucket = new TokenBucket($redis, 'api_rate_limit', 10, 1); // 容量10,每秒1个令牌

if ($bucket->consume()) {
    echo "请求通过";
} else {
    echo "请求被限制";
}

纯PHP实现

如果不依赖Redis,可以使用纯PHP实现单机版令牌桶。

class LocalTokenBucket {
    private $capacity;
    private $tokens;
    private $rate;
    private $lastTime;

    public function __construct($capacity, $rate) {
        $this->capacity = $capacity;
        $this->tokens = $capacity;
        $this->rate = $rate;
        $this->lastTime = microtime(true);
    }

    public function consume($tokens = 1) {
        $now = microtime(true);
        $elapsed = $now - $this->lastTime;
        $this->tokens = min($this->capacity, $this->tokens + $elapsed * $this->rate);
        $this->lastTime = $now;

        if ($this->tokens >= $tokens) {
            $this->tokens -= $tokens;
            return true;
        }
        return false;
    }
}

// 使用示例
$bucket = new LocalTokenBucket(10, 1); // 容量10,每秒1个令牌
if ($bucket->consume()) {
    echo "请求通过";
} else {
    echo "请求被限制";
}

实现要点

令牌补充逻辑 计算自上次请求以来的时间差,补充相应数量的令牌: $newTokens = elapsedTime * rate$

令牌消耗检查 每次请求时检查是否有足够令牌: $if (currentTokens >= requestedTokens) { allow } else { deny }$

原子性操作 Redis实现使用Lua脚本确保操作的原子性,防止并发问题。

容量限制 补充令牌时不超过桶的容量: $currentTokens = min(capacity, currentTokens + newTokens)$

这两种实现方式分别适用于不同场景,Redis版本适合分布式系统,纯PHP版本适合单机应用。根据实际需求选择合适的实现方式。

php实现 令牌桶

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

相关文章

php实现打印功能

php实现打印功能

PHP 实现打印功能的方法 PHP 可以通过多种方式实现打印功能,具体取决于打印的目标(如打印机、PDF、网页等)和需求(如直接打印、生成打印预览等)。以下是几种常见的实现方式: 使用 JavaSc…

php实现图片上传

php实现图片上传

实现图片上传的基本步骤 创建HTML表单用于文件上传,表单需设置enctype="multipart/form-data"属性,确保文件数据正确传输。 <form action="uploa…

php实现表单

php实现表单

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

php实现聊天

php实现聊天

实现 PHP 聊天功能的方法 使用 WebSocket 和 PHP 实现实时聊天 WebSocket 是一种全双工通信协议,适合实现实时聊天功能。PHP 可以通过 Ratchet 库实现 WebSo…

php实现的分页

php实现的分页

PHP 实现分页的方法 基本分页逻辑 分页的核心在于计算总页数、当前页码以及数据偏移量。假设每页显示 10 条数据: $current_page = isset($_GET['page']) ? (…

php怎么实现登录功能

php怎么实现登录功能

数据库准备 创建用户表存储登录信息,通常包括用户名、密码(需加密)等字段。示例SQL: CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY…