2012-04-16 10 views
12

Estoy desarrollando una API REST simple usando Spring 3 + Spring MVC. La autenticación se realizará a través de OAuth 2.0 o autenticación básica con un token de cliente utilizando Spring Security. Esto todavía está en debate. Todas las conexiones serán forzadas a través de una conexión SSL.¿Cómo implementar la limitación de velocidad basada en un token de cliente en Spring?

He estado buscando información sobre cómo implementar la limitación de velocidad, pero no parece que haya mucha información disponible. La implementación necesita ser distribuida, ya que funciona en múltiples servidores web.

Por ejemplo, si hay tres servidores api A, B, C y los clientes están limitados a 5 solicitudes por segundo, entonces un cliente que realiza 6 solicitudes como tal encontrará la solicitud de C rechazada con un error.

A recieves 3 requests \ 
B receives 2 requests | Executed in order, all requests from one client. 
C receives 1 request /

Se necesita trabajo basado en una muestra incluida en la solicitud, ya que un cliente puede ser hacer peticiones en nombre de muchos usuarios, y cada usuario debe velocidad limitada en lugar de la dirección IP del servidor.

La configuración será de varios (2-5) servidores web detrás de un equilibrador de carga HAProxy. Hay un Cassandra respaldado, y se usa memcached. Los servidores web se ejecutarán en Jetty.

Una posible solución podría ser escribir un filtro de Spring Security personalizado que extraiga el token y compruebe cuántas solicitudes se han realizado con él en los últimos X segundos. Esto nos permitiría hacer algunas cosas, como diferentes límites de velocidad para diferentes clientes.

¿Alguna sugerencia sobre cómo se puede hacer? ¿Existe una solución existente o tendré que escribir mi propia solución? No he hecho mucha infraestructura de sitios web antes.

+0

Estás en el camino correcto con la idea del filtro. Dado que ya está utilizando memcached, debería ser sencillo. – sourcedelica

+0

Parecer un filtro podría ser el camino a seguir. Encontré un artículo útil sobre la implementación de un sistema de intervalos para que pueda verificar el uso de la API durante los últimos X minutos/segundos -> http://chris6f.com/rate-limiting-with-redis. Utiliza redis pero los principios deben ser similares a Memcache o Cassandra. –

Respuesta

0

Evitaría modificar el código de nivel de aplicación para cumplir este requisito si es posible.

He echado un vistazo a la documentación de HAProxy LB nada demasiado obvio allí, pero el requisito puede justificar una investigación completa de las ACL.

Al poner HAProxy a un lado, una arquitectura posible es poner un Servidor Web Apache al frente y usar un plugin Apache para hacer la limitación de velocidad. Las solicitudes que superan el límite se rechazan por adelantado y los servidores de aplicaciones en el nivel detrás de Apache se separan de las preocupaciones por el límite de velocidad haciéndolos más simples. También podría considerar servir contenido estático del servidor web.

Ver la respuesta a esta pregunta How can I implement rate limiting with Apache? (requests per second)

espero que esto ayude. Rob

+1

Gracias por la respuesta. El proyecto no utiliza actualmente Apache WebServer, Jetty se usa para desplegar archivos war. Hay una serie de guerras existentes que conforman la aplicación actual, y la API simplemente será otra aplicación web ejecutada en Jetty. Sería un poco de esfuerzo cambiar a Apache, así que estoy tratando de evitarlo si es posible. También parece que los mods de Apache están enfocados en IP en lugar de limitación de token. Hacerlo en el código de la aplicación es un problema, pero parece ofrecer el mayor control. Puede ser lento, pero no está destinado a detener ataques DDoS. –

0

Puede poner límites de velocidad en varios puntos del flujo (generalmente cuanto más alto mejor) y el enfoque general que tiene tiene mucho sentido. Una opción para la implementación es usar 3scale para hacerlo (http://www.3scale.net) - limita la velocidad, análisis, claves administradas, etc. y funciona con un complemento de código (el plugin de Java está aquí: https://github.com/3scale/3scale_ws_api_for_java) que empuja o colocando algo así como Barniz (http://www.varnish-cache.org) en la tubería y tener que aplicar límites de velocidad.

0

También estaba pensando en soluciones similares hace un par de días.Básicamente, prefiero la solución "central-controlled" para guardar el estado de la solicitud del cliente en el entorno distribuido.

En mi aplicación, utilizo un "session_id" para identificar el cliente de solicitud. Luego, cree un filtro de servlet o Spring HandlerInterceptorAdapter para filtrar la solicitud, luego verifique el "session_id" con el depósito de datos centralizado, que podría ser memcached, redis, cassandra o zookeeper.

Cuestiones relacionadas