Автор оригинала: Ganesh Pagade.
1. Введение
Весеннее облако Netflix Зуул является открытым исходным кодом шлюз, который обертывает Netflix Зуул . Он добавляет некоторые специфические функции для приложений Spring Boot. К сожалению, ограничение скорости не предоставляется из коробки.
В этом учебнике мы изумим Весеннее облако Зуул RateLimit который добавляет поддержку запросов ограничения скорости.
2. Конфигурация Maven
В дополнение к зависимости от весеннего облака Netflix Зуул, мы должны добавить Весеннее облако Зуул RateLimit к заявлению нашего пом.xml :
org.springframework.cloud spring-cloud-starter-netflix-zuul com.marcosbarbero.cloud spring-cloud-zuul-ratelimit 2.2.0.RELEASE
3. Пример контроллера
Firstly, let’s create a couple of REST endpoints on which we will apply the rate limits.
Below is a simple Spring Controller class with two endpoints:
@Controller @RequestMapping("/greeting") public class GreetingController { @GetMapping("/simple") public ResponseEntitygetSimple() { return ResponseEntity.ok("Hi!"); } @GetMapping("/advanced") public ResponseEntity getAdvanced() { return ResponseEntity.ok("Hello, how you doing?"); } }
As we can see, there is no code specific to rate limit the endpoints. This is because we’ll configure that in our Zuul properties within the application.yml file. Thus, keeping our code decoupled.
4. Куул Свойства
Во-вторых, давайте добавим следующие свойства Зуула в нашем application.yml файл:
zuul: routes: serviceSimple: path: /greeting/simple url: forward:/ serviceAdvanced: path: /greeting/advanced url: forward:/ ratelimit: enabled: true repository: JPA policy-list: serviceSimple: - limit: 5 refresh-interval: 60 type: - origin serviceAdvanced: - limit: 1 refresh-interval: 2 type: - origin strip-prefix: true
Under zuul.routes we provide the endpoint details. And under zuul.ratelimit.policy-list, we provide the rate limit configurations for our endpoints. The limit property specifies the number of times the endpoint can be called within the refresh-interval .
Как мы видим, мы добавили ограничение скорости 5 запросов на 60 секунд для сервисSimple конечная точка. В отличие от этого, serviceAdvanced имеет ограничение скорости 1 запрос в течение 2 секунд.
тип конфигурация определяет, какому подходу ограничения скорости мы хотим следовать. Вот возможные значения:
- происхождение – ограничение скорости в зависимости от запроса на происхождение пользователя
- URL – ограничение скорости, основанное на пути запроса службы ниже по течению
- пользовательские – ограничение скорости на основе подлинного имени пользователя или «анонимного»
- Нет значения – действует как глобальная конфигурация на одну службу. Чтобы использовать этот подход, просто не устанавливайте парам ‘тип’
5. Тестирование лимита тарифов
5.1. Запрос в пределах предела ставки
Далее, давайте проверить предел скорости:
@Test public void whenRequestNotExceedingCapacity_thenReturnOkResponse() { ResponseEntityresponse = restTemplate.getForEntity(SIMPLE_GREETING, String.class); assertEquals(OK, response.getStatusCode()); HttpHeaders headers = response.getHeaders(); String key = "rate-limit-application_serviceSimple_127.0.0.1"; assertEquals("5", headers.getFirst(HEADER_LIMIT + key)); assertEquals("4", headers.getFirst(HEADER_REMAINING + key)); assertThat( parseInt(headers.getFirst(HEADER_RESET + key)), is(both(greaterThanOrEqualTo(0)).and(lessThanOrEqualTo(60000))) ); }
Здесь мы делаем один звонок к конечной точке /приветствие/простое . Запрос является успешным, так как он находится в пределах предела скорости.
Другим ключевым моментом является то, с каждым ответом мы получаем обратно заготовки предоставления нам дополнительную информацию о пределе скорости. Для выше запроса, мы хотели бы получить следующие заготовки:
X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1: 5 X-RateLimit-Remaining-rate-limit-application_serviceSimple_127.0.0.1: 4 X-RateLimit-Reset-rate-limit-application_serviceSimple_127.0.0.1: 60000
Другими словами:
- X-RateLimit-Limit-«ключ»: предельный настроен для конечной точки
- X-RateLimit-Оставаясь-ключ: оставшееся количество попыток вызвать конечную точку
- X-RateLimit-Перезагрузка-ключ: оставшееся количество миллисекунд обновление интервала настроен для конечной точки
Кроме того, если мы сразу же огонь же конечной точкой снова, мы могли бы получить:
X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1: 5 X-RateLimit-Remaining-rate-limit-application_serviceSimple_127.0.0.1: 3 X-RateLimit-Reset-rate-limit-application_serviceSimple_127.0.0.1: 57031
Обратите внимание на уменьшенное оставшееся количество попыток и оставшееся количество миллисекунд.
5.2. Запрос о превышении лимита ставки
Давайте посмотрим, что произойдет, когда мы превышаем предел скорости:
@Test public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException { ResponseEntityresponse = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); assertEquals(OK, response.getStatusCode()); for (int i = 0; i < 2; i++) { response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); } assertEquals(TOO_MANY_REQUESTS, response.getStatusCode()); HttpHeaders headers = response.getHeaders(); String key = "rate-limit-application_serviceAdvanced_127.0.0.1"; assertEquals("1", headers.getFirst(HEADER_LIMIT + key)); assertEquals("0", headers.getFirst(HEADER_REMAINING + key)); assertNotEquals("2000", headers.getFirst(HEADER_RESET + key)); TimeUnit.SECONDS.sleep(2); response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); assertEquals(OK, response.getStatusCode()); }
Здесь мы называем конечную точку /приветствие/продвинутые дважды в быстрой последовательности. Так как мы настроили ограничение скорости как один запрос на 2 секунды, второй вызов не . В результате код ошибки 429 ( Слишком много запросов) возвращается клиенту.
Ниже приведены заготовки, возвращенные по достигнутой ставке:
X-RateLimit-Limit-rate-limit-application_serviceAdvanced_127.0.0.1: 1 X-RateLimit-Remaining-rate-limit-application_serviceAdvanced_127.0.0.1: 0 X-RateLimit-Reset-rate-limit-application_serviceAdvanced_127.0.0.1: 268
После этого мы спим 2 секунды. Это обновление интервала настроен для конечной точки. Наконец, мы снова заготовим конечную точку и получим успешный ответ.
6. Пользовательский генератор ключей
Мы можем настроить ключи, отправленные в заголовке ответа, используя пользовательский генератор ключей. Это полезно, поскольку приложению, возможно, потребуется контролировать ключевую стратегию, выходят за рамки вариантов, предлагаемых тип свойство.
Например, это можно сделать, создав пользовательский RateLimitKeyГенератор реализация. Мы можем добавить дополнительные квалификаторы или что-то совершенно другое:
@Bean public RateLimitKeyGenerator rateLimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) { return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) { @Override public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) { return super.key(request, route, policy) + "_" + request.getMethod(); } }; }
Вышеупомянутый код притяяяет имя метода REST к ключу. Например:
X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1_GET: 5
Другим ключевым моментом является то, что RateLimitKeyГенератор фасоль будет автоматически настроена весна-облако-zuul-ratelimit .
7. Обработка пользовательских ошибок
Структура поддерживает различные реализации для хранения данных ограничения скорости. Например, предоставляются Spring Data JPA и Redis. По умолчанию сбои просто регистрируются как ошибки с помощью По умолчаниюРейтерЭррорХэндлер класс.
Когда нам нужно обрабатывать ошибки по-разному, мы можем определить пользовательский RateLimiterErrorHandler боб:
@Bean public RateLimiterErrorHandler rateLimitErrorHandler() { return new DefaultRateLimiterErrorHandler() { @Override public void handleSaveError(String key, Exception e) { // implementation } @Override public void handleFetchError(String key, Exception e) { // implementation } @Override public void handleError(String msg, Exception e) { // implementation } }; }
Похожи на RateLimitKeyГенератор фасоль, RateLimiterErrorHandler фасоль также будет автоматически настроена.
8. Заключение
В этой статье мы увидели, как оценить ограничение API с помощью весеннего облака Netflix Зуул и весеннего облака Зуул RateLimit.
Как всегда, полный код этой статьи можно найти более на GitHub .