php使用redis实现的滑动时间窗口的限流算法

本文介绍了如何在PHP中结合Redis实现滑动时间窗口限流算法,通过提供Swoole的压测脚本示例来阐述具体应用。

欢迎光临小弟的博客maliweb.top

/**
 * 滑动窗口限流
 * Class SlidingWindow
 * @package App\Common
 */
class SlidingWindow
{
	protected $timeStamp;                       //当前的时间戳

	protected $_is_open_minimum_check = false;  //是否开启最小精度检查 默认不开启

	protected $_minimum_time_range_size = 1;    // 最小限制范围精度单位秒钟
	protected $_minimum_time_range_qps  = 50;   // 最小范围精度对应的时间内允许的请求数量

	protected $_maximum_time_range_size = 60;   // 最大限制范围单位秒钟
	protected $_maximum_time_range_qps = 3000;  // 最大限制范围对应的时间内允许的请求数量

	protected $key = 'sliding_window';

	/** @var $redis \Redis */
	public $redis;

	public function __construct($redis)
	{
		$this->timeStamp = time();
		$this->redis = $redis;
	}

	//设置是否开启最小精度的检查 false为关闭 true为开启
	public function setOpenMininumCheck($open)
	{
		$this->_is_open_minimum_check = $open;
		return $this;
	}

	//设置最小精度时间 单位秒
	public function setMininumTime($time)
	{
		$this->_minimu
基于Redis滑动窗口流量控制算法可以通过Redis的ZSET数据结构实现。具体实现步骤如下: 1. 定义一个时间窗口,例如1分钟,将这个时间窗口分成多个小时间片,例如每秒一个时间片。 2. 每个时间片对应一个ZSET,ZSET中的元素为请求的时间戳,分值为1。 3. 当有请求到达时,将请求的时间戳作为元素插入到当前时间片对应的ZSET中。 4. 统计整个时间窗口内的请求总数,可以通过遍历所有时间片对应的ZSET并累加元素数量得到。 5. 如果请求总数超过了限流阈值,则拒绝本次请求。 6. 为了避免ZSET无限增长,需要定期清理过期的时间片。 下面是一个PHP实现的示例代码: ```php class SlidingWindow { private $redis; private $windowSize; private $limit; public function __construct($redis, $windowSize, $limit) { $this->redis = $redis; $this->windowSize = $windowSize; $this->limit = $limit; } public function hit() { $now = microtime(true); $key = $this->getKey($now); $this->redis->zAdd($key, $now, $now); $this->redis->expire($key, $this->windowSize); $count = $this->getCount(); if ($count > $this->limit) { throw new Exception('Rate limit exceeded'); } } private function getKey($now) { $start = floor($now / $this->windowSize) * $this->windowSize; $end = $start + $this->windowSize - 1; return "sliding_window:{$start}:{$end}"; } private function getCount() { $now = microtime(true); $start = floor($now / $this->windowSize) * $this->windowSize; $end = $start + $this->windowSize - 1; $keys = []; for ($i = $start; $i <= $end; $i += 1) { $keys[] = $this->getKey($i); } $this->redis->zUnion($key, $keys); $this->redis->expire($key, $this->windowSize); return $this->redis->zCard($key); } } // 使用示例 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $windowSize = 60; // 时间窗口为60秒 $limit = 100; // 限流阈值为100个请求 $slidingWindow = new SlidingWindow($redis, $windowSize, $limit); try { $slidingWindow->hit(); echo 'Request accepted'; } catch (Exception $e) { echo 'Request rejected: ' . $e->getMessage(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值