Микросервисы SpringCloud Alibaba на практике 12 — Ограничение тока шлюза

Java

Введение: В предыдущих главах мы ограничили ток на уровне микросервиса и интегрировали Spring Cloud Gateway, Основное содержание этой главы — перенести текущую функцию ограничения с микросервиса на уровень шлюза.

Собственное ограничение тока SpringCloud Gateway

Собственное ограничение тока Springcloud Gateway в основном реализовано на основе фильтров, и мы можем напрямую использовать встроенные фильтры.RequestRateLimiterGatewayFilterFactory,В настоящее времяRequestRateLimiterGatewayFilterFactoryреализация зависит отRedis, так что мы также вводимspring-boot-starter-data-redis-reactive.

POM-зависимости

<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>

Конфигурация ограничения тока

spring:
  cloud:
    gateway:
      routes:
      - id: account-service
        uri: lb://account-service
        order: 10000
        predicates:
        - Path=/account-service/**
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1
            redis-rate-limiter.burstCapacity: 3
            key-resolver: "#{@ipKeyResolver}" 

В основном настройте три основных параметра:

  • redis-rate-limiter.replenishRate :
    Сколько запросов пользователю разрешено обрабатывать в секунду
  • redis-rate-limiter.burstCapacity :
    Емкость корзины токенов, максимальное количество запросов, разрешенных для выполнения за одну секунду.
  • key-resolver :
    Имя объекта bean-компонента синтаксического анализатора для регулирования ключей. Он использует выражения SpEL для получения объектов bean-компонентов из контейнера Spring на основе #{@beanName}.

Настроить бины

/**
* 自定义限流标志的key,多个维度可以从这里入手
* exchange对象中获取服务ID、请求信息,用户信息等
*/
@Bean
KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

Sentinel регулирование

Мы говорили об использовании Sentinel в предыдущих главах.Если вам непонятно, вы можете прочитать предыдущие главы.Здесь мы в основном говорим об интеграции со шлюзом SpringCloud.

Начиная с версии 1.6.0, Sentinel предоставляет модуль адаптации для Spring Cloud Gateway, который может обеспечить текущее ограничение в двух измерениях ресурсов:

  • измерение маршрута: то есть запись маршрута, настроенная в файле конфигурации Spring, имя ресурса является соответствующей настройкой routeId
  • Параметр API: пользователи могут использовать API, предоставляемый Sentinel, для настройки некоторых групп API.

Ниже приведены наши шаги по интеграции

POM-зависимости

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

Поскольку nacos необходимо использовать в качестве центра конфигурации Sentinel, он также вводитсяsentinel-datasource-nacos

Начальная конфигурация

...
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 10.0.10.48:8858
      eager: true
      datasource:
        ds:
          nacos:
            server-addr: 10.0.10.48:8848
            data-id: gateway-sentinel-flow
            group-id: DEFAULT_GROUP
            rule-type: gw-flow
...

Вот в основном соответствующая конфигурация часового, полученная из центра конфигурации nacos.gateway-sentinel-flowВ файле конфигурации текущим типом ограничения является тип шлюза gw-flow.

Конфигурация ограничения тока

Создано на общедоступной странице управления конфигурацией nacosdata-idдляgateway-sentinel-flowконфигурационный файл (формат json), дающийaccount-serviceа такжеproduct-serviceДобавьте правила регулирования.

[
  {
    "resource": "account-service",
    "count": 5,
    "grade": 1,
    "paramItem": {
        "parseStrategy": 0
    }
  },
  {
    "resource": "product-service",
    "count": 2,
    "grade": 1,
    "paramItem": {
        "parseStrategy": 0
    }
  }
]

После завершения настройки запустите проект шлюза, войдите в консоль Sentinel и просмотрите текущие правила ограничения:

image.png

Инструкции по настройке:

以客户端IP作为限流因子
public static final int PARAM_PARSE_STRATEGY_CLIENT_IP = 0;
以客户端HOST作为限流因子
public static final int PARAM_PARSE_STRATEGY_HOST = 1;
以客户端HEADER参数作为限流因子
public static final int PARAM_PARSE_STRATEGY_HEADER = 2;
以客户端请求参数作为限流因子
public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;
以客户端请求Cookie作为限流因子
public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;

Тест ограничения тока

Множественный доступ через шлюзaccount-serviceСервисный тестhttp://localhost:8090/account/getByCode/javadailyПроверьте эффект ограничения тока:

Исключение пользовательского ответа

Логика реализации по умолчанию исключения текущего ограничения шлюза SpringCloud:SentinelGatewayBlockExceptionHandler, вы можете просмотреть исходный код, чтобы найти ключевой код ненормального ответа следующим образом.

Поскольку серверная часть службы возвращает формат ответа JSON, нам нужно изменить исходный ответ об исключении и изменить его наResultDataФормат ответа класса. Чтобы реализовать эту функцию, вам нужно только написать новый обработчик исключений и внедрить новый обработчик исключений в класс конфигурации SpringCloud GateWay.

  • собственный обработчик исключенийCustomGatewayBlockExceptionHandler
public class CustomGatewayBlockExceptionHandler implements WebExceptionHandler {
	...
    /**
     * 重写限流响应,改造成JSON格式的响应数据
     * @author javadaily
     * @date 2020/1/20 15:03
     */
    private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
        ServerHttpResponse serverHttpResponse = exchange.getResponse();
        serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        ResultData<Object> resultData = ResultData.fail(ReturnCode.RC200.getCode(), ReturnCode.RC200.getMessage());
        String resultString = JSON.toJSONString(resultData);
        DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(resultString.getBytes());
        return serverHttpResponse.writeWith(Mono.just(buffer));
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        } else {
            return !BlockException.isBlockException(ex) ? Mono.error(ex) : this.handleBlockedRequest(exchange, ex).flatMap((response) -> this.writeResponse(response, exchange));
        }
    }
   ...
}

Вы можете напрямую скопироватьSentinelGatewayBlockExceptionHandlerкласс, а затем изменитьwriteResponseинтерфейс метода

  • Измените класс конфигурации шлюза и внедритеCustomGatewayBlockExceptionHandler
@Configuration
public class GatewayConfiguration {
	...
    /**
     * 注入自定义网关异常
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public CustomGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the custom block exception handler .
        return new CustomGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }
	...
}
  • Добавьте конфигурацию в файл bootstrap.yml
spring:
  main:
    allow-bean-definition-overriding: true
  • Повторный тест, текущие результаты ограничения ответа следующие
{
	"message": "服务开启限流保护,请稍后再试!",
	"status": 200,
	"success": false,
	"timestamp": 1579509123946
}

Ограничение тока не вступает в силу

Если вы обнаружите, что текущее ограничение уровня шлюза не действует во время использования, вы можете запустить службу шлюза в режиме отладки, а затем отфильтровать шлюз.SentinelGatewayFilterЧтобы отладить метод фильтрации в , я обнаружил, что идентификатор шлюза, полученный дозорным, не соответствует тому, что мы настроили.account-service, но добавилCompositeDiscoveryClient_префикс, как показано на следующем рисунке:

Итак, нам нужно изменитьgateway-sentinel-flowКонфигурация нашего ресурса также префиксная, измененная конфигурация выглядит следующим образом:

[{
	"resource": "CompositeDiscoveryClient_account-service",
	"count": 5,
	"grade": 1,
	"paramItem": {
		"parseStrategy": 0
	}
}, {
	"resource": "CompositeDiscoveryClient_product-service",
	"count": 2,
	"grade": 1,
	"paramItem": {
		"parseStrategy": 0
	}
}]

При использовании jemter для тестирования интерфейса обнаружено, что шлюз может нормально ограничивать ток.

После вышеуказанных шагов мы можем удалить текущую ограничивающую конфигурацию внутреннего уровня микросервиса и позволить уровню шлюза взять на себя текущую ограничивающую функцию.

Ну что, друзья мои, содержание этого выпуска здесь полностью. Вы же видите, что здесь одноклассники все отличники. Следующее повышение и прибавка к зарплате будете у вас! Если вы считаете, что эта статья полезна для вас, отсканируйте приведенный ниже QR-код, чтобы добавить подписку.

«Ретвитнуть» плюс «просмотреть», чтобы выработать полезную привычку! Увидимся в следующий раз!

Серия статей SpringCloud Alibaba