Domanda

Gli utenti legittimi del mio sito di tanto in tanto martello il server con richieste API che causano risultati indesiderati. Voglio istituire un limite di non più di dire un'API chiamata ogni 5 secondi o n chiamate al minuto (non hanno ancora capito il limite esatto). Potrei ovviamente accedo ogni chiamata API in un DB e fare il calcolo su ogni richiesta per vedere se sono oltre il limite, ma tutto questo overhead in più su ogni richiesta sarebbe sconfiggendo lo scopo. Quali sono gli altri metodi intensivo di risorse meno ho potuto usare per istituire un limite? Sto utilizzando PHP / Apache / Linux, per quello che vale.

È stato utile?

Soluzione

Ok, non c'è modo di fare quello che ho chiesto, senza qualsiasi scrive al server, ma posso almeno eliminare la registrazione di ogni singola richiesta. Un modo è quello di utilizzare il metodo di limitazione "leaky bucket", dove tiene traccia solo dell'ultima richiesta ($last_api_request) ed un rapporto tra il numero di richieste / limite per il periodo di tempo ($minute_throttle). Il secchio che perde mai reimposta il suo contatore (a differenza della valvola a farfalla del Twitter API che azzera ogni ora), ma se il secchio si riempie (utente ha raggiunto il limite), si deve attendere secondi n per il secchio per svuotare un po 'prima di poter fare un'altra richiesta di . In altre parole è come un limite rotolamento: se vi sono richieste precedenti entro i tempi, vengono lentamente fuoriuscita del bucket; esso si limita solo se si riempire il secchio.

Questo frammento di codice calcolerà un nuovo valore $minute_throttle su ogni richiesta. Ho specificato il minuto in $minute_throttle perché è possibile aggiungere manette per qualsiasi periodo di tempo, come ad esempio oraria, giornaliera, ecc ... anche se più di uno sarà avviare rapidamente per rendere più confusione per gli utenti.

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

Altri suggerimenti

È possibile controllare la velocità con la algoritmo del token bucket , che è paragonabile al secchio che perde algoritmo. Si noti che si dovrà condividere lo stato del secchio (vale a dire la quantità di gettoni) sui processi (o qualunque ambito si desidera controllare). Così si potrebbe desiderare di pensare a bloccaggio per evitare condizioni di gara.

La buona notizia: ho fatto tutto questo per voi: banda-gas / token-bucket

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

Non so se questa discussione è ancora vivo o no, ma vorrei suggerire di tenere queste statistiche nella cache memoria come memcached. Ciò consentirà di ridurre l'overhead di registrare la richiesta al DB, ma servono ancora lo scopo.

soluzione più semplice sarebbe quella di appena dare ad ogni chiave API un numero limitato di richieste per 24 ore, e ripristinare ad un certo noto, fisso, il tempo.

Se si esauriscono le loro richieste API (es. Il contatore raggiunge lo zero, o il limite, a seconda della direzione che stai contando), smettono di servire loro dati prima non viene azzerato il loro contatore.

In questo modo, sarà in loro interesse a non Martello con le richieste.

Lei dice che "tutti i thos aeree in più su ogni richiesta sarebbero sconfiggendo lo scopo", ma non sono sicuro che sia corretta. non è lo scopo di prevenire martellamento del server? Questo è probabilmente il modo in cui vorrei applicarla, come in realtà richiede solo una rapida lettura / scrittura. Si potrebbe anche Farm i controlli del server API per un diverso DB / disco se si erano preoccupati per le prestazioni.

Tuttavia, se si desidera che le alternative, si dovrebbe verificare mod_cband , un modulo di apache di terze parti progettata per aiutare nella limitazione della larghezza di banda. Pur essendo principalmente per limitare la larghezza di banda, può acceleratore in base alle richieste al secondo pure. Non ho mai usato, quindi non sono sicuro di che tipo di risultati si otterrebbe. Ci fu un altro modulo chiamato mod-acceleratore pure, ma quel progetto sembra essere chiusa oggi, e non è mai uscito per qualsiasi cosa sopra la serie di Apache 1.3.

Oltre alla realizzazione da zero si è anche possibile dare un'occhiata a un'infrastruttura API come 3scale ( http: //www.3scale .net ) che fa limitazione della velocità, nonché una serie di altre cose (analisi etc.). C'è un plugin PHP per esso:. https://github.com/3scale/3scale_ws_api_for_php

È anche possibile attaccare qualcosa come Varnish davanti delle API e fare il tasso di API di limitazione del genere.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top