思路
1、限流需求中存在一个滑动的时间窗口,而zset的score值可以用来圈定时间窗口,窗口之外的数据都可以删除
2、zset的value需要是一个唯一的值,只需要保证唯一性即可
3、如果按照某个接口单位时间允许访问次数,那么key可以用接口路径,如果是限制单个用户那么key可以结合userId
4、缺点是内存有可能占用过多,如果用户60s之内不能请求超过100w次,那么就需要在zset中添加100w个值
<?php
class Limit
{
public $redis = null;
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect("172.17.185.131",6379);
}
public function uuid()
{
$str="123456790abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$uuid="";
for($i=0;$i<10;$i++) {
$uuid.=$str[mt_rand(0,strlen($str)-1)];
}
return $uuid;
}
public function setLimit($userId)
{
$time = time();
$pipe=$this->redis->multi(2);
$pipe->zRemRangeByRank("limit:{$userId}",0,$time-60*1000);
$val = $this->uuid();
$ret = $pipe->zAdd("limit:{$userId}",time(),$val);
$pipe->zCard("limit:{$userId}");
$ret = $pipe->exec();
$pipe->close();
return $ret;
}
}
$redis = new Limit();
$ret= $redis->setLimit()[2];
if ($ret>1000) {
return false;
}
|