Как реализовать ограничение скорости на основе токена клиента в Spring?
Я разрабатываю простой REST API, используя Spring 3 + Spring MVC. Аутентификация будет выполняться через OAuth 2.0 или basic auth с помощью токена клиента с помощью Spring Security. Это все еще обсуждается. Все соединения будут принудительно подключены через SSL-соединение.
Я искал информацию о том, как реализовать ограничение скорости, но похоже, что там много информации. Реализация должна быть распределена, поскольку она работает на нескольких веб-серверах.
Например, если есть три сервера api, A, B, C и клиенты ограничены 5 запросами в секунду, то клиент, который делает 6 запросов, как это, найдет запрос на C, отклоненный с ошибкой.
A recieves 3 requests \
B receives 2 requests | Executed in order, all requests from one client.
C receives 1 request /
Он должен работать на основе токена, включенного в запрос, поскольку один клиент может делать запросы от имени многих пользователей, и каждый пользователь должен быть ограничен лимитом, а не IP-адрес сервера.
Настройка будет представлять собой несколько (2-5) веб-серверов за балансировщиком HAProxy. Существует Cassandra, и memcached используется. Веб-серверы будут работать на Jetty.
Одним из возможных решений может быть создание настраиваемого фильтра безопасности Spring, который извлекает токен и проверяет, сколько запросов было выполнено с ним за последние X секунд. Это позволило бы нам сделать некоторые вещи, как разные лимиты ставок для разных клиентов.
Любые предложения о том, как это можно сделать? Есть ли существующее решение или мне придется написать собственное решение? Раньше я не делал много инфраструктуры веб-сайта.
Ответы
Ответ 1
Я бы не стал модифицировать код уровня приложения для удовлетворения этого требования, если это вообще возможно.
Я просмотрел HAProxy. Документация LB здесь не слишком очевидна, но это требование может потребовать полного изучения ACL.
Включение HAProxy в одну сторону, возможная архитектура заключается в том, чтобы вывести Apache WebServer спереди и использовать плагин Apache для ограничения скорости. Запросы с превышением лимита отклонены, а серверы приложений в уровне за Apache затем отделены от ограничений по скорости, что упрощает их. Вы также можете использовать статический контент с веб-сервера.
См. ответ на этот вопрос Как я могу реализовать ограничение скорости с помощью Apache? (запросы в секунду)
Надеюсь, это поможет.
Rob
Ответ 2
Вы могли бы установить лимиты ставок в разных точках потока (как правило, чем выше, тем лучше), а общий подход, который у вас есть, имеет большой смысл. Одним из вариантов реализации является использование 3scale для этого (http://www.3scale.net) - он ограничивает лимиты, аналитику, управление ключами и т.д. И работает либо с плагином кода (плагин Java здесь: https://github.com/3scale/3scale_ws_api_for_java), который толкает или помещает что-то вроде Varnish (http://www. varnish-cache.org) в соответствии с действующими ограничениями.
Ответ 3
Лучше всего, если вы реализуете ratelimit с помощью REDIS. Для получения дополнительной информации смотрите Ограничение скорости js Пример.
Ответ 4
Я думал о подобных решениях пару дней назад. В принципе, я предпочитаю "центральное контролируемое" решение для сохранения состояния запроса клиента в распределенной среде.
В моем приложении я использую "session_id" для идентификации клиента запроса. Затем создайте фильтр сервлета или spring HandlerInterceptorAdapter, чтобы отфильтровать запрос, затем проверьте "session_id" на репозиторий данных с центральным управлением, который может быть memcached, redis, cassandra или zookeeper.