При перепечатке просьба указывать источник:www.fangzhipeng.comЭта статья взята изБлог Фан Чжипэна
В системе с высокой степенью параллелизма часто возникает необходимость ограничения тока в системе, с одной стороны, чтобы предотвратить перегрузку сервера большим количеством запросов, приводящих к недоступности сервиса, а с другой стороны , это для предотвращения сетевых атак.
Обычные методы ограничения тока, такие как Hystrix, подходят для изоляции пула резьбы, превышают нагрузку пула резьбы и используют логику предохранителей. В общем приложении сервера, такие как контейнер Tomcat, параллелизм также контролируется ограничением количества его потоков; также есть средняя скорость времени времени для управления потоком. Распространенные ограничивающие широкие широты включают, например, ограничение тока по IP, ограничением тока по URI и ограничением тока по частоте доступа пользователей.
Как правило, ограничение тока выполняется на уровне шлюза, например Nginx, Openresty, kong, zuul, Spring Cloud Gateway и т. д. Это также можно сделать на уровне приложения через Aop.
В этой статье подробно рассматривается, как реализовать регулирование в Spring Cloud Gateway.
Общие алгоритмы ограничения тока
Алгоритм счетчика
Алгоритм счетчика немного прост и груб, чтобы использовать счетчик для ограничения тока.В общем, мы будем ограничивать количество запросов, которые могут пройти за одну секунду.Например, текущее ограничение qps равно 100. Идея Алгоритм заключается в том, чтобы начать отсчет времени с первого запроса, в течение 1 с каждый раз, когда приходит запрос, счетчик увеличивается на 1. Если накопленное число достигает 100, все последующие запросы будут отклонены. По истечении 1 с восстановите счет до 0 и перезапустите счет. Конкретная реализация может быть следующей: для каждого вызова службы можно использовать метод AtomicLong#incrementAndGet(), чтобы добавить 1 к счетчику и вернуть последнее значение, а также сравнить последнее значение с пороговым значением. У этого метода реализации, я думаю, все знают, есть недостаток: если я передал 100 запросов в первые 10 мс единицы времени 1 с, то в следующие 990 мс я могу только отказать в запросе, мы называем это явление «за». явление спайка"
алгоритм дырявого ведра
Чтобы устранить «феномен Spike», алгоритм утечек ведра может использовать неверный алгоритм ведра для ограничения тока. Название элементарного алгоритма ведра очень ярче. Существует контейнер внутри алгоритма, который похож на воронку Используется в жизни. Когда приходит запрос, он эквивалентен наливанию воды. В воронку, а затем медленно и равномерно вытекают из маленького отверстия на нижнем конце. Независимо от потока выше, скорость потока ниже остается прежней. Независимо от того, насколько нестабильный сервисный звонок - это алгоритм утечки ведра, чтобы ограничить ток, и запрос обрабатывается каждые 10 миллисекунд. Поскольку скорость обработки фиксирована, скорость входящих запросов неизвестна, и многие запросы могут войти внезапно. Запросы, которые не были обработаны во времени, будут в первую очередь в ведре. Так как это ведро, должна быть емкость предел. Если ведро заполнено, то новые входящие запросы отбрасываются.
С точки зрения алгоритма очередь может быть подготовлена для запроса на хранение, чтобы регулярно получать дополнительные запросы из очереди с помощью пула потоков (ScheduledExecutorService) и выполняться один раз, может быть получено многократное параллельное выполнение.
У этого алгоритма есть и недостатки после использования: он не справляется с кратковременным пакетным трафиком.
Алгоритм ведра токенов
В некотором смысле алгоритм ведра с маркерами является усовершенствованием алгоритма с дырявым ведром.Алгоритм ведра может ограничивать скорость вызовов запросов, в то время как алгоритм ведра с маркерами может ограничивать среднюю скорость вызовов, допуская при этом определенную степень внезапных изменений. вызов. В алгоритме ведра токенов есть ведро для хранения фиксированного количества токенов. В алгоритме есть механизм для помещения токенов в ведро с определенной скоростью. Каждый вызов запроса должен сначала получить токен. Только когда токен получен, он может продолжить выполнение. В противном случае выберите ожидание доступного токена или отклоните его напрямую. Действие по высвобождению токена непрерывное, если количество токенов в ведре достигает верхнего предела, токен будет сброшен, поэтому бывает такая ситуация, в ведре всегда большое количество доступных токенов, и входящий запрос можно напрямую Получить токен и выполнить его.Например установить qps равным 100.После завершения инициализации текущего ограничителя в ведре уже 100 токенов.На данный момент сервис не запущен полностью , Когда запуск завершен, предоставляется внешняя служба.Ограничитель тока может выдержать мгновенные 100 запросов. Следовательно, только когда в ведре нет токена, запрос будет ожидать, что эквивалентно выполнению с определенной скоростью.
Идея реализации: можно подготовить очередь для сохранения токенов, и периодически генерировать токены через пул потоков и помещать их в очередь, каждый раз при приходе запроса получать токен из очереди и продолжать выполнение.
Текущее ограничение Spring Cloud Gateway
В Spring Cloud Gateway есть фильтр Filter, поэтому вы можете реализовать три вышеуказанных фильтра самостоятельно в «предварительном» типе фильтра. Однако в качестве самой базовой функции шлюза Spring Cloud Gateway официально предоставляет класс RequestRateLimiterGatewayFilterFactory, который реализует метод ведра маркеров для сценариев Redis и Lua. Конкретная логика реализации находится в классе RequestRateLimiterGatewayFilterFactory, а сценарий lua находится в папке, как показано ниже:
Конкретный исходный код здесь описываться не будет. Читатели могут просмотреть его самостоятельно. Объем кода небольшой. Сначала мы объясним, как использовать встроенную фабрику фильтров ограничения тока в Spring Cloud Gateway для достижения ограничения тока. в виде кейса.
Сначала в pom-файл проекта вносятся стартовые зависимости gateway и реактивные зависимости redis, код выглядит следующим образом:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifatId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
Выполните следующую настройку в файле конфигурации:
server:
port: 8081
spring:
cloud:
gateway:
routes:
- id: limit_route
uri: http://httpbin.org:80/get
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@hostAddrKeyResolver}'
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 3
application:
name: gateway-limiter
redis:
host: localhost
port: 6379
database: 0
В приведенном выше файле конфигурации программа для назначенного порта 8081, информация о конфигурации Redis и конфигурация фильтра RequestRateLimiter ограничителя потока, для конфигурации фильтра требуются три параметра:
- BurstCapacity, Token Barrel Total Phower.
- пополнитьRate, средняя скорость заполнения корзины токенов в секунду.
- key-resolver, имя bean-объекта преобразователя для регулируемого ключа. Он использует выражения SpEL для получения объектов bean-компонентов из контейнера Spring на основе #{@beanName}.
KeyResolver должен реализовать метод разрешения.Например, чтобы ограничить ток на основе имени хоста, вам нужно использовать hostAddress для оценки. После реализации KeyResolver необходимо зарегистрировать бин этого класса в Ioc-контейнере.
public class HostAddrKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
@Bean
public HostAddrKeyResolver hostAddrKeyResolver() {
return new HostAddrKeyResolver();
}
Вы можете ограничить ток в соответствии с uri.В настоящее время код KeyResolver выглядит следующим образом:
public class UriKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getURI().getPath());
}
}
@Bean
public UriKeyResolver uriKeyResolver() {
return new UriKeyResolver();
}
Вы также можете ограничить поток на основе измерения пользователя:
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
Используйте jmeter для измерения давления, настройте 10threads для циклического запроса lcoalhost:8081, а интервал цикла составляет 1 с. По результатам стресс-теста видно, что часть запросов проходит, а часть запросов терпит неудачу. Используйте клиент Redis для просмотра ключей, существующих в Redis. следующее:
Видно, что RequestRateLimiter использует Redis для ограничения тока и хранит 2 ключа в redis. Обратите внимание на значение этих двух ключей и посмотрите исходный код lua.
Загрузка исходного кода
Github.com/forephotos/sp день ...
использованная литература
cloud.spring.IO/spring - уродливый...
woohoo.spring4all.com/article/138…
Сканировать и поддерживать автор
(Просьба указывать автора и источник при перепечатке статей с этого сайтаБлог Фан Чжипэна)