当前位置:首页 > PHP

php实现 令牌桶

2026-03-13 05:20:14PHP

php实现 令牌桶

php实现 令牌桶

令牌桶算法简介

令牌桶算法是一种常用的流量控制算法,通过固定速率生成令牌,请求需获取令牌才能执行,未获取令牌的请求会被限制或排队。适用于API限流、接口防刷等场景。

PHP实现令牌桶

基本实现思路

  1. 维护一个容器存储令牌(可用Redis或内存变量)
  2. 设定令牌生成速率和桶容量
  3. 每次请求时检查可用令牌数量
  4. 有足够令牌则扣除并允许请求,否则拒绝

基于Redis的实现

<?php
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("hmset", key, "time", lastTime, "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_limit', 10, 1); // 容量10,速率1个/秒

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

纯PHP实现(无Redis)

<?php
class MemoryTokenBucket {
    private $tokens;
    private $capacity;
    private $rate;
    private $lastTime;

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

    public function consume($tokens = 1) {
        $now = microtime(true);
        $elapsed = $now - $this->lastTime;
        $this->lastTime = $now;

        $this->tokens = min(
            $this->capacity,
            $this->tokens + $elapsed * $this->rate
        );

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

        return false;
    }
}

// 使用示例
$bucket = new MemoryTokenBucket(10, 1); // 容量10,速率1个/秒
if ($bucket->consume()) {
    echo "请求通过";
} else {
    echo "请求被限流";
}
?>

实现要点

  1. 使用Redis的Lua脚本保证原子性操作
  2. 精确计算时间差来补充令牌
  3. 支持突发流量(桶容量大于生成速率时)
  4. 分布式环境下必须使用Redis等共享存储

性能优化建议

  1. 对高频访问的令牌桶可增加本地缓存
  2. 批量获取令牌时建议使用Lua脚本
  3. 多键操作时考虑使用Redis管道
  4. 根据业务场景调整桶容量和生成速率

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

相关文章

php实现购物车

php实现购物车

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

php实现跳转

php实现跳转

PHP 实现页面跳转的方法 在 PHP 中实现页面跳转有多种方式,以下是常见的几种方法及其适用场景: 使用 header() 函数 通过 header() 函数发送 HTTP 头部信息实现跳转。注意…

php 实现跳转

php 实现跳转

PHP 实现页面跳转的方法 在PHP中,实现页面跳转可以通过多种方式完成,以下是几种常用的方法: 使用header函数 header函数是PHP中最常用的跳转方法,通过发送HTTP头部信息实现跳转。…

无限分类实现 php

无限分类实现 php

无限分类的实现方法 无限分类通常用于构建多层级结构的数据,如商品分类、部门架构等。以下是几种常见的实现方式: 邻接列表模式(Adjacency List) 邻接列表是最简单的实现方式,通过在每个记录…

php实现文章

php实现文章

PHP实现文章管理功能 在PHP中实现文章管理功能通常涉及数据库操作、表单处理和页面展示。以下是实现文章管理的基本步骤: 数据库设计 创建articles表,包含字段如id、title、conten…

php数据库实现

php数据库实现

PHP 连接 MySQL 数据库 使用 mysqli 扩展连接 MySQL 数据库: <?php $servername = "localhost"; $username = "usernam…