2015-03-10

使用 SSDB 来实现操作频率限制

Views: 67595 | 5 Comments

在 Web 开发中, 经常需要实现操作频率限制的功能, 以避免单个用户过度地消耗某项资源, 或者消除安全隐患. 例如, 限制某 IP 刷新页面的频率, 限制一个用户投票只能投一次, 等等.

要实现操作频率限制, 就要用到存储. 使用 SSDB 来存储, 可以支持海量用户的操作频率限制, 而且代码非常简洁高效.

// 操作次数限制函数: 限制 uid 在 period 秒内能操作 action 最多 max_count 次.
// 如果超过限制, 返回 false.
static function act_limit($uid, $action, $max_count, $period){
	$now = time();
	$expire = intval($now / $period) * $period + $period;
	$ttl = $expire - $now;
	$key = "act_limit|$uid|$action";
	$count = Util::ssdb()->incr($key);
	Util::ssdb()->expire($key, $ttl);
	if($count === false || $count > $max_count){
		return false;
	}
	return true;
}

如代码注释, 这段代码可直接用于操作频率限制, 其中 uid 参数不一定是用户的 UID, 可以是任意的区别用户身份的字符串, 可以是 IP 地址, 邮件地址, 手机号等等.

SSDB 的 incr 是原子操作, 所以即使并发执行这个函数, 也不会有问题.

而且, 也不一定是限制用户的操作频率, 也可以限制某个资源的访问频率, 如限制某个手机号发送验证码的次数, 无论是哪个用户操作的, 可避免对同一个手机号的骚扰.

用法如下:

$test = act_limit($ip, 'login', 3, 60);
if(!$test){
	// 超过频率限制
}else{
	// 正常操作
}

Related posts:

  1. SSDB 支持 TTL 过期机制
  2. SSDB 支持位(BIT)操作
  3. SSDB 源码分析 – 网络框架概述
  4. SSDB 提供了非常详细的 PHP API 文档
  5. SSDB 现在已经支持 Java 语言了!
Posted by ideawu at 2015-03-10 17:49:02

5 Responses to "使用 SSDB 来实现操作频率限制"

  • 1s钟大概300的短连接,会偶尔出现几次的timeout,我们3.5s超时。
    这个是什么情况。 Reply
  • 你好, 就是我修改了 simplessdb的连接超时设置, 但是还是报错
    Fatal error: Uncaught exception ‘SSDBException’ with message ‘Connection lost’ in , 要怎么处理呢?

    $this->mySSDB = new SimpleSSDB($ip, $port, 2000); Reply
  • 有个问题,这样只实现了阶段性的频率限制,比如我们定义$period为10s,那么这个功能实现的是1s-10s内限制$max_count次,过了第10s就给清零然后重新计数了,然后11s-20s再从新技术。
    而严格上来讲,应该是流式的,像第1s-10s,1s-11s,2s-12s这样的区间。
    当然产品可能并不是这样的需求 :) Reply
    @blankyao: 是的, 是有这个问题. 不过, 实际上不需要严格的每一个区间都是限制. Reply
  • 不错,恰当好用! Reply

Leave a Comment