Los usuarios legítimos de mi sitio a veces martillan el servidor con solicitudes API que causan resultados no deseados. Quiero establecer un límite de no más de una llamada de API cada 5 segundos o n llamadas por minuto (aún no he calculado el límite exacto). Obviamente, pude registrar todas las llamadas de la API en un DB y hacer el cálculo en cada solicitud para ver si están por encima del límite, pero toda esta carga adicional en CADA solicitud sería contraria al propósito. ¿Cuáles son otros métodos menos intensivos en recursos que podría usar para establecer un límite? Estoy usando PHP/Apache/Linux, por lo que vale.¿Cómo acelero los usuarios de la API de mi sitio?
Respuesta
Ok, no hay forma de hacer lo que solicité sin cualquier escribe en el servidor, pero al menos puedo eliminar el registro de cada solicitud. Una forma es utilizar el método de aceleración "leaky bucket", donde solo hace un seguimiento de la última solicitud() y una proporción del número de solicitudes/límite para el marco de tiempo ($minute_throttle
). El cubo con fugas nunca restablece su contador (a diferencia del acelerador de Twitter API que se restablece cada hora), pero si el depósito se llena (el usuario alcanzó el límite), deben esperar n
segundos para que el depósito se vacíe un poco antes de poder realizar otra solicitud . En otras palabras, es como un límite móvil: si hay solicitudes previas dentro del marco de tiempo, se están filtrando lentamente del cubo; solo te restringe si llenas el cubo.
Este fragmento de código calculará un nuevo valor $minute_throttle
en cada solicitud. Especifiqué minutos en $minute_throttle
porque puede agregar aceleradores para cualquier período de tiempo, como por hora, por día, etc. ... aunque más de uno empezará a confundir rápidamente a los usuarios.
$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);
¿Puedes explicar por qué '$ minute_limit' sería nulo? – nrathaus
Creo que debería ser '$ minute_throttle', ya que proviene de DB. – Sljux
¿Has pensado en extraer el RateLimiter en su propia clase? – mblaettermann
Usted dice que "todos los gastos indirectos adicionales en CADA solicitud estarían derrotando el propósito", pero no estoy seguro de que sea correcto. ¿No es el propósito de evitar el martilleo de su servidor? Esta es probablemente la forma en que lo implementaría, ya que solo requiere una lectura/escritura rápida. Incluso podría sacrificar las verificaciones del servidor de la API a una base de datos/disco diferente si estuviera preocupado por el rendimiento.
Sin embargo, si desea alternativas, debe consultar mod_cband, un módulo de apache de terceros diseñado para ayudar en la aceleración del ancho de banda. A pesar de ser principalmente para la limitación del ancho de banda, también puede acelerarse en función de las solicitudes por segundo. Nunca lo he usado, así que no estoy seguro de qué tipo de resultados obtendrías. Hubo otro módulo llamado mod-throttle también, pero ese proyecto parece estar cerrado ahora, y nunca fue lanzado para nada por encima de la serie Apache 1.3.
Sí, probablemente tenga que guardar algo en el disco ... preferiblemente no todas las solicitudes de registro. Podría guardar la última solicitud API exitosa y asegurarme de que sea n segundos más tarde que eso. – scotts
solución más simple sería simplemente dar a cada clave de API un número limitado de solicitudes por 24 horas, y restablecerlos en algún conocido, fijo, el tiempo.
Si agota sus solicitudes API (es decir, el contador llega a cero, o el límite, dependiendo de la dirección en la que esté contando), deje de mostrarles datos hasta que restablezca su contador.
De esta manera, será en su el mejor interés para no golpearlo con las solicitudes.
Además de la implementación desde cero, también puede consultar la infraestructura de API como 3scale (http://www.3scale.net) que limita la velocidad, así como un montón de otras cosas (análisis, etc.). Hay un plugin de PHP para él: https://github.com/3scale/3scale_ws_api_for_php.
También puede pegar algo así como Varnish enfrente de la API y hacer la limitación de la tasa de API de esa manera.
No sé si este hilo todavía está vivo o no, pero sugeriría mantener estas estadísticas en la memoria caché como memcached. Esto reducirá la sobrecarga de registrar la solicitud en la base de datos, pero aún sirve para el propósito.
Acepto completamente y lo implementamos así como también es atómico. Puedes usar algo como AWS elasticache para almacenarlos y luego tener un cronjob simplemente registra los resultados agregados luego en una base de datos. En realidad, tenemos una pequeña instancia de memcached por servidor para hacer incrementos y luego lave/incremente esto a elasticache una vez por minuto, de esa forma tampoco moverá el cuello de botella a elasticache. – Ross
@Kedar todavía puede registrar todas las llamadas en un archivo para diferentes tipos de análisis ', lo que no molestaría a su base de datos, simplemente poniendo en cola las escrituras en el búfer del disco. – kommradHomer
¿Redis sería una mejor solución? ¿Está en ram pero también no volátil? – BeardedGeek
Puede controlar la frecuencia con el token bucket algorithm, que es comparable al algoritmo del cubo con fugas. Tenga en cuenta que deberá compartir el estado del depósito (es decir, la cantidad de tokens) sobre los procesos (o el alcance que desee controlar). Por lo que es posible que desee pensar en bloquear para evitar las condiciones de carrera.
La buena noticia: Hice todo eso para usted: bandwidth-throttle/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();
}
Gracias por el enlace al algoritmo del cubo de fichas: sin eso no me habría dado cuenta de que el cubo con fugas era un algoritmo de buena fe. – Colin
- 1. ¿Cómo puedo integrar los inicios de sesión de los usuarios de mi sitio en phpBB?
- 2. ¿Cómo acelero DbSet.Add()?
- 3. ¿Cómo se integran los "Usuarios" en mi modelo DDD con la autenticación de usuarios?
- 4. ¿Cómo puedo saber los usuarios en línea de mi sitio web?
- 5. ¿Cómo evitar que los usuarios inicien sesión en mi sitio más de una sesión?
- 6. Creación de una URL personal para todos los usuarios a mi sitio
- 7. ¿Cuál es un método efectivo para prohibir a los usuarios de mi sitio?
- 8. Sitio web. Videos de VoteUp o VoteDown. ¿Cómo restringir la votación de los usuarios varias veces?
- 9. Deshabilitar el aviso "Recordar mi contraseña" para los usuarios que visitan el sitio
- 10. Mostrar el tiempo según la ubicación de los usuarios
- 11. ¿Cómo encontrar la ubicación de los usuarios durante una visita al sitio web?
- 12. La mejor manera de que los usuarios descarguen un archivo de mi sitio web: http o ftp
- 13. Cómo crear API de sitio web
- 14. Usando la API de EWS para buscar entre los diferentes buzones de los usuarios
- 15. ¿Cómo asegurar mi API web?
- 16. cómo proteger mi sitio web
- 17. ¿La API de Google Calendar es adecuada para mi problema?
- 18. ¿Cómo obtener intereses de los usuarios?
- 19. ¿La mejor práctica para los usuarios que limitan la velocidad de una API REST?
- 20. sistema de administración de usuarios para un sitio web
- 21. Actualizar los resultados de búsqueda de Google para Mi sitio
- 22. Cómo ver la solicitud en el violín a mi sitio y desde mi sitio iis 5
- 23. ¿Cómo autenticar usuarios en un sitio y pasar credenciales a otro sitio? (Autenticación de Windows, ASP.Net)
- 24. ¿Cómo acelero Visual Studio con una gran cantidad de proyectos?
- 25. Mailchimp API (.NET Wrapper) - Usuarios de suscripción automática
- 26. ¿Hay un complemento jQuery para los globos de ayuda para los usuarios noveles de un sitio?
- 27. ¿Cómo impido que Chrome deje en color amarillo los cuadros de entrada de mi sitio?
- 28. ¿Cómo debo almacenar la configuración de mi sitio ASP.NET MVC?
- 29. de comercio electrónico de pagos - ¿Cómo pago los usuarios?
- 30. Asegurar mi sitio
Se trata sólo de un vendaje, mientras que permite ajustar la API o añadir más servidores? Es muy peligroso quitarle algo a/poner restricciones a los desarrolladores ... –
No, estoy tratando de establecer límites razonables para que el sitio sea sostenible. Agregar capacidad de servidor para algunos usuarios excesivamente celosos no es parte del plan. – scotts