2010-03-25 3 views
2

je suis venu avec ceci:Quelle est la meilleure approche pour limiter la fréquence d'une opération coûteuse avec PHP et Memcached?

 
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); 

Toute pensée à ce sujet, serait-il avantageux de dormir pendant quelques secondes si l'IP se trouve dans Memcached?

Répondre

1

Cela semble être une très bonne solution, bien que vous puissiez peut-être utiliser la fonction session_id() au lieu de l'adresse IP. De cette façon, si vous traitez avec des personnes derrière un routeur, vous ne pourrez pas bloquer les personnes qui ne martèlent pas. Bien que le session_id puisse facilement être régénéré par eux en effaçant leurs cookies, mais cela leur prendra probablement plus de temps que d'attendre les 5 secondes. Vous ne voulez certainement pas dormir dans un script PHP car cela ne fait que retarder un processus PHP en dormant.

Vous pouvez configurer un autre élément memcache pour suivre le nombre de fois qu'ils ont atteint l'avertissement, par exemple une période de 1 heure, puis vous pouvez faire quelque chose de plus dur ou consigner les informations utilisateur.

Bien qu'il soit préférable d'essayer d'optimiser le fonctionnement, ce n'est pas aussi coûteux (plus facile à dire qu'à faire).

+0

Merci, je sais que je pouvais faire un peu plus, mais je vraiment besoin de quelque chose de rapide et sale. – mmattax

0

Vous pouvez utiliser le token bucket algorithm pour limiter le débit. Je l'ai implémenté pour vous: bandwidth-throttle/token-bucket

Je vous recommande également de ne pas dormir, car vous bloquez les ressources de votre serveur. Il suffit de sortie avec le code d'état 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(); 

Mais si vous voulez vraiment vous dormir pouvez le faire avec un BlockingConsumer:

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