Consumo efficiente di un servizio a tariffa limitata

5

Quindi il mio caso esatto è che ho ~ 1400 domini su un server di bind antico, auto-ospitato e sto cercando di migrarli a un servizio ospitato. Il problema è che l'API del servizio ospitato ha un limite di velocità di 150 richieste per 300 secondi e ogni dominio richiederà almeno 3 richieste di migrazione. [Nota: questa API non fornisce informazioni sulle quote, semplicemente smette di funzionare con un messaggio di errore generico. :I ]

Se dovessi semplicemente codificare a caldo un intervallo di 2 secondi tra le richieste, avrei finito con 6+ secondi di chiamate API, oltre a 2 secondi aggiuntivi per recuperare / riformattare i record dal server precedente. Questo mi fa salire a circa 3,1 ore per la migrazione, che è una domanda pesante.

Un'altra alternativa che ho considerato è stata l'aggiunta di una variabile $last_call che potrei utilizzare per calcolare un sonno da aggiungere fino a 2 secondi dall'ultima chiamata, ma che non tiene conto del tempo trascorso al di fuori del client API / chiamate.

Infine ho provato a mantenere un elenco di timestamp millisecondi che rappresentano ciascuna chiamata, contando quanti si sono verificati negli ultimi 300 secondi e dividendo la finestra equamente tra loro. Tuttavia, ho scoperto che questo tende a provocare un sonno più lungo del necessario all'inizio della prima finestra, un sonno freneticamente piccolo alla fine e una frequenza di chiamata leggermente inferiore al limite configurato. Questo si ripete in un ciclo e non sembra ponderare molto anche nel corso di un paio d'ore.

Esiste un metodo o un algoritmo particolare che sarebbe adatto per coordinare più equamente queste richieste entro il limite di velocità specificato?

    
posta Sammitch 13.10.2016 - 20:39
fonte

2 risposte

0

Quindi, dopo molte difficoltà, ho usato un po 'di matematica per capire una funzione che avrebbe dormito per la giusta quantità di tempo rispetto alla richiesta data, e mi permettesse di aumentarla esponenzialmente verso la fine.

Se esprimiamo il sonno come:

y = e^( (x-A)/B )

dove A e B sono valori arbitrari, quindi la somma di tutti i sleep, M , da 0 a N richieste sarebbe:

M = 0∫N e^( (x-A)/B ) dx

Questo è equivalente a:

M = B * e^(-A/B) * ( e^(N/B) - 1 )

e può essere risolto rispetto ad A come:

A = B * ln( -1 * (B - B * e^(N/B)) / M )

Mentre risolvere per B sarebbe molto più utile, dato che la specifica di A ti consente di definire in quale punto il grafico aumenta in modo aggressivo, la soluzione è matematicamente complessa, e non sono stato in grado di risolverlo da solo o trova qualcuno altro che possa.

/**
 * @param int $period   M, window size in seconds
 * @param int $limit    N, number of requests permitted in the window
 * @param int $used x, current request number
 * @param int $bias B, "bias" value
 */
protected static function ratelimit($period, $limit, $used, $bias=20) {
    $period = $period * pow(10,6);
    $sleep = pow(M_E, ($used - self::biasCoeff($period, $limit, $bias))/$bias);
    usleep($sleep);
}

protected static function biasCoeff($period, $limit, $bias) {
    $key = sprintf('%s-%s-%s', $period, $limit, $bias);
    if( ! key_exists($key, self::$_bcache) ) {
        self::$_bcache[$key] = $bias * log( -1 * ( ($bias - $bias * pow(M_E, $limit/$bias)) / $period ) );
    }
    return self::$_bcache[$key];
}

Con un po 'di complicazioni ho scoperto che B = 20 sembra essere un default decente, anche se non ho basi matematiche per questo. Qualcosa di simile slope mumble mumble esponenziale bs bs .

Inoltre, se qualcuno vuole risolvere questa equazione per B per me Ho una taglia su su math.stackexchange .

    
risposta data 04.11.2016 - 18:20
fonte
0

Un consumatore produttore. Gestisci il produttore in questo modo non devi tenere conto del tempo di esecuzione nel consumatore.

    
risposta data 16.10.2016 - 15:23
fonte

Leggi altre domande sui tag