Frage

Die berechtigten Benutzer von meiner Seite gelegentlich den Server mit API-Anfragen hämmern, die zu unerwünschten Ergebnissen führen. Ich möchte eine Grenze von nicht mehr als etwa ein API-Aufruf alle 5 Sekunden auf die Einführung oder n Anrufe pro Minute (nicht die genaue Grenze noch herausgefunden). Ich könnte natürlich jeden API-Aufruf in einem DB anmelden und bei jeder Anfrage der Berechnung tun, um zu sehen, ob sie über die Grenze sind, aber all dieser zusätzliche Aufwand auf jeden Wunsch wäre es, den Zweck zu besiegen. Was sind andere weniger ressourcenintensive Methoden, die ich eine Grenze einzuleiten verwenden könnte? Ich bin mit PHP / Apache / Linux, für das, was es wert ist.

War es hilfreich?

Lösung

Ok, gibt es keine Möglichkeit zu tun, was ich ohne darum gebeten alle Schreibvorgänge auf den Server, aber ich kann zumindest beseitigen jede einzelne Anforderung zu protokollieren. Eine Möglichkeit besteht darin, die „leaky bucket“ Drosselungsverfahren verwendet wird, wo es hält nur der letzten Anforderung Spur ($last_api_request) und ein Verhältnis der Anzahl von Anforderungen / Grenze für den Zeitrahmen ($minute_throttle). Die undichten Eimer setzt nie seine Zähler (im Gegensatz zu der Drossel Twitter-API, die jede Stunde zurücksetzt), aber wenn der Eimer voll ist (Benutzer die Grenze erreicht), müssen sie n Sekunden für den Eimer warten ein wenig zu leeren, bevor sie einen weiteren Antrag stellen können . Mit anderen Worten ist es wie ein Rolllimit: wenn vorherige Anfragen innerhalb des Zeitrahmens sind, werden sie langsam von der Schaufel austritt; es schränkt Sie nur, wenn Sie den Eimer füllen.

Dieser Code-Schnipsel wird einen neuen $minute_throttle Wert bei jeder Anfrage berechnet werden. I angegebene Minuten in $minute_throttle weil Sie drosselt für einen beliebigen Zeitraum, wie Stunden hinzufügen können, täglich, etc ... obwohl mehr als ein schnell es für die Benutzer verwirrend zu machen beginnt.

$minute = 60;
$minute_limit = 100; # users are limited to 100 requests/minute
$last_api_request = $this->get_last_api_request(); # get from the DB; in epoch seconds
$last_api_diff = time() - $last_api_request; # in seconds
$minute_throttle = $this->get_throttle_minute(); # get from the DB
if ( is_null( $minute_limit ) ) {
    $new_minute_throttle = 0;
} else {
    $new_minute_throttle = $minute_throttle - $last_api_diff;
    $new_minute_throttle = $new_minute_throttle < 0 ? 0 : $new_minute_throttle;
    $new_minute_throttle += $minute / $minute_limit;
    $minute_hits_remaining = floor( ( $minute - $new_minute_throttle ) * $minute_limit / $minute  );
    # can output this value with the request if desired:
    $minute_hits_remaining = $minute_hits_remaining >= 0 ? $minute_hits_remaining : 0;
}

if ( $new_minute_throttle > $minute ) {
    $wait = ceil( $new_minute_throttle - $minute );
    usleep( 250000 );
    throw new My_Exception ( 'The one-minute API limit of ' . $minute_limit 
        . ' requests has been exceeded. Please wait ' . $wait . ' seconds before attempting again.' );
}
# Save the values back to the database.
$this->save_last_api_request( time() );
$this->save_throttle_minute( $new_minute_throttle );

Andere Tipps

Sie können die Geschwindigkeit steuern, mit dem Token-Bucket-Algorithmus , die dem undichten Eimer vergleichbar ist Algorithmus. Beachten Sie, dass Sie den Status des Eimers teilen müssen (das heißt die Menge von Token) über Prozesse (oder was auch immer Umfang Sie steuern möchten). So können Sie über Sperren zu vermeiden Rennbedingungen zu denken, interessiert sein könnten.

Die gute Nachricht: Ich habe alles für Dich: Bandbreite Gas / Token-Eimer

use bandwidthThrottle\tokenBucket\Rate;
use bandwidthThrottle\tokenBucket\TokenBucket;
use bandwidthThrottle\tokenBucket\storage\FileStorage;

$storage = new FileStorage(__DIR__ . "/api.bucket");
$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();
}

Ich weiß nicht, ob dieser Thread noch am Leben ist oder nicht, aber ich würde diese Statistiken im Speicher-Cache zu halten, legt nahe, wie Memcached. Dadurch wird der Aufwand für die Protokollierung der Anfrage an die DB reduzieren, sondern dienen immer noch den Zweck.

Einfachste Lösung wäre, nur jedem API-Schlüssel über eine begrenzte Anzahl von Anfragen pro 24 Stunden zu geben, und setzen Sie sie an einem gewissen bekannt, fest, Zeit.

Wenn sie ihre API-Anforderungen erschöpfen (dh. Der Zähler Null erreicht, oder die Grenze, abhängig von der Richtung Sie zählen), unterbrechen Sie Daten dienen, bis Sie ihre Zähler zurücksetzen.

Auf diese Weise wird es in sein ihr Interesse nicht Sie mit Anfragen hämmern.

Sie sagen, dass „all thos zusätzlichen Aufwand bei jeder Anfrage würde den Zweck werden zu besiegen“, aber ich bin nicht sicher, ob das stimmt. Ist das nicht der Zweck Hämmer des Servers zu verhindern? Dies ist wahrscheinlich die Art, wie ich es umsetzen würde, wie es wirklich benötigt nur einen schnellen Lese- / Schreib. Man könnte sogar Farm aus dem API-Server überprüft, auf eine andere DB / Scheibe, wenn Sie über die Leistung besorgt wurden.

Wenn Sie jedoch Alternativen wollen, sollten Sie überprüfen mod_cband , ein Drittanbieter-Apache-Modul entworfen in Drosselung der Bandbreite zu unterstützen. Trotz vor allem für die Bandbreite einschränkend, es kann basierend auf Anforderungen pro Sekunde Drossel als gut. Ich habe es nie benutzt, so dass ich nicht sicher bin, was für Ergebnisse, die Sie bekommen würde. Es war eine weitere Modul mod-Drossel auch genannt, aber das Projekt wird nun geschlossen zu werden, und war nie für irgendetwas über der Apache 1.3-Serie veröffentlicht.

Neben der Implementierung von Grund auf neu, Sie können auch einen Blick auf API-Infrastruktur wie 3scale nehmen ( http: //www.3scale .net ), die tut Rate sowie ein paar andere Sachen zu begrenzen (Analytik etc.). Es gibt eine PHP für das Plugin. https://github.com/3scale/3scale_ws_api_for_php

Sie können auch so etwas wie Lack direkt vor der API-Stick und die API-Rate wie die Begrenzung tun.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top