Zaimplementowałem mechanizm dławienia biednego człowieka w phunction używając samego APC, używam go w następujący sposób:
// allow 60 requests every 30 seconds
// each request counts as 1 (expensive operations can use higher values)
// keep track of IPs by REMOTE_ADDR (ignore others)
$throttle = ph()->Throttle($ttl = 30, $exit = 60, $count = 1, $proxy = false);
if ($throttle === true)
{
// IP exceded 30 requests in the last 60 seconds, die() here
}
else
{
// $throttle is a float
// number of requests in the last 30 seconds / 30 seconds
/*
1 req / 30 = 0,033 sec
5 req / 30 = 0,166 sec
10 req / 30 = 0,333 sec
15 req / 30 = 0,5 sec
20 req / 30 = 0,666 sec
25 req / 30 = 0,833 sec
30 req / 30 = 1 sec
*/
usleep(intval(floatval($throttle) * 1000000));
}
Używam tego na moim kontrolerze Front-Controller i przekazuję wartość do mojej metody routingu, ale to już inna historia.
Najważniejsze jest to, że jeśli używasz APC, możesz przechowywać rzeczy bardzo szybko w pamięci i przy niewielkim zużyciu pamięci, ponieważ APC stosuje metodologię FILO. Jeśli potrzebujesz znacznie dłuższych limitów czasu, możesz rozważyć użycie czegoś, co nie jest oparte na pamięci.
BTW:MySQL obsługuje tabele z silnikiem MEMORY.
Problem z sleep()
:
Typowy serwer WWW Apache z zainstalowanym PHP jako moduł zużywa około 10 MB pamięci RAM na instancję, aby uniknąć przekroczenia dostępnej pamięci RAM, istnieją pewne ustawienia Apache, które możesz skonfigurować, aby ograniczyć maksymalną liczbę instancji, które Apache może uruchomić.
Problem polega na tym, że sleep()
, ta instancja jest nadal aktywna i przy wystarczającej liczbie żądań może skończyć się zjedzeniem wszystkich dostępnych slotów, aby uruchomić nowe serwery, co sprawi, że Twoja witryna będzie niedostępna do czasu zakończenia niektórych oczekujących żądań.
Nie ma sposobu na obejście tego z PHP AFAIK, więc ostatecznie to zależy od Ciebie.
Zasada jest taka sama w przypadku ograniczania przepustowości w całym systemie:
function systemWide($ttl = 86400, $exit = 360)
{
if (extension_loaded('apc') === true)
{
$key = array(__FUNCTION__);
if (apc_exists(__FUNCTION__) !== true)
{
apc_store(__FUNCTION__, 0, $ttl);
}
$result = apc_inc(__FUNCTION__, 1);
if ($result < $exit)
{
return ($result / $ttl);
}
return true;
}
return false;
}