Consumo eficiente de um serviço de taxa limitada

5

Portanto, meu caso exato é que tenho ~ 1400 domínios em um antigo servidor de bind auto-hospedado e estou procurando migrá-los para um serviço hospedado. O problema é que a API do serviço hospedado tem um limite de taxa de 150 solicitações por 300 segundos e cada domínio exigirá pelo menos três solicitações para migrar. [Nota: Esta API não fornece nenhuma informação de quota, ela simplesmente pára de funcionar com uma mensagem de erro genérica. :I ]

Se eu fosse simplesmente codificar um intervalo de 2 segundos entre as solicitações, terminaria com 6 ou mais segundos de chamadas de API, além de mais ~ 2 segundos para recuperar / reformatar os registros do servidor legado. Isso me atinge em torno de 3,1 horas para a migração, que é uma pergunta pesada.

Outra alternativa que considerei foi adicionar uma variável $last_call que eu poderia usar para calcular um sono para adicionar até dois segundos desde a última chamada, mas isso ainda não leva em conta o tempo gasto fora do cliente da API / chamadas.

Por último, tentei manter uma lista de timestamps de milissegundos representando cada chamada, contando quantos ocorreram nos últimos 300 segundos e dividindo a janela igualmente entre eles. No entanto, descobri que isso tende a resultar em suspensões mais longas do que as necessárias no início da primeira janela, freneticamente pequenas no final e com uma taxa de chamadas um pouco abaixo do limite configurado. Isso se repete em um ciclo e não parece ter uma média muito grande, mesmo ao longo de algumas horas.

Existe um método ou algoritmo específico que seria adequado para coordenar mais uniformemente essas solicitações dentro do limite de taxa determinado?

    
por Sammitch 13.10.2016 / 20:39
fonte

2 respostas

0

Então, depois de muito debater, usei alguns cálculos para descobrir uma função que duraria a soma correta do tempo em relação à solicitação dada e permitisse que eu aumentasse exponencialmente até o final.

Se nós expressamos o sono como:

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

em que A e B são valores arbitrários, a soma de todos os suspensos, M , de 0 a N solicitações seria:

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

Isso é equivalente a:

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

e pode ser resolvido em relação a A como:

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

Embora a solução para B seja muito mais útil, uma vez que especificar A permite definir em que ponto o gráfico aumenta agressivamente, a solução para isso é matematicamente complexa e não consegui resolvê-lo sozinho ou encontre alguém else que 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];
}

Com um pouco de ajustes, descobri que B = 20 parece ser um padrão decente, embora eu não tenha uma base matemática para isso. Algo algo declive mumble mumble exponencial bs bs .

Além disso, se alguém quiser resolver essa equação para B para mim Eu tenho uma recompensa em matemática.stackexchange .

    
por 04.11.2016 / 18:20
fonte
0

Um consumidor produtor. Acelere o produtor dessa forma você não precisa levar em conta o tempo de execução no consumidor.

    
por 16.10.2016 / 15:23
fonte