代码之家  ›  专栏  ›  技术社区  ›  mmattax

使用php&memcached限制昂贵操作的最佳方法是什么?

  •  2
  • mmattax  · 技术社区  · 14 年前

    我想到了这个:

    if($prog->memcache) {
        $r = $prog->memcache->get("ratelimit:{$_SERVER['REMOTE_ADDR']}");
        if(!empty($r)) $prog->errorClose('This IP has been flagged for potential abuse.');
    }
    
    foo(); // the thing we're rate limiting...
    
    if($prog->memcache)
        $prog->memcache->set("ratelimit:{$_SERVER['REMOTE_ADDR']}", 1, 0, 5);
    

    有没有想过,如果在memcached中找到ip,睡眠几秒钟会有好处?

    2 回复  |  直到 14 年前
        1
  •  1
  •   Klinky    14 年前

    似乎是一个很好的解决方案,不过也许您可以使用session_id()而不是IP地址。这样,如果你和路由器后面的人打交道,你就不会阻止那些没有敲打的人。虽然清除cookies可以很容易地重新生成会话id,但这样做可能比仅仅等待5秒要花更长的时间。您绝对不想在php脚本中睡觉,因为它只会在睡觉时占用php进程。

    您可以设置另一个memcache项来跟踪他们在1小时内达到警告的次数,然后您可以执行更严厉的操作,或者记录用户信息。

    不过,最好是尽量优化操作,这样成本就不会那么高(说起来容易做起来难)。

        2
  •  0
  •   Markus Malkusch    9 年前

    你可以使用 token bucket algorithm 用于速率限制。我已经为你实现了: bandwidth-throttle/token-bucket

    我也建议不要睡觉,因为你会阻塞服务器的资源。只需使用http状态代码429退出:

    use bandwidthThrottle\tokenBucket\Rate;
    use bandwidthThrottle\tokenBucket\TokenBucket;
    use bandwidthThrottle\tokenBucket\storage\MemcachedStorage;
    
    $storage = new MemcachedStorage("resource", $memcached);
    $rate    = new Rate(10, Rate::SECOND);
    $bucket  = new TokenBucket(10, $rate, $storage);
    $bucket->bootstrap(10);
    
    if (!$bucket->consume(1, $seconds)) {
        http_response_code(429);
        header(sprintf("Retry-After: %d", floor($seconds)));
        exit();
    }
    
    foo();
    

    但是如果你真的想睡觉你可以用 BlockingConsumer 以下内容:

    $consumer = new BlockingConsumer($bucket);
    $consumer->consume(1);
    foo();