Практический отчет Spring Cloud Gateway2.0

Spring Boot Spring

Ваши лайки - моя самая большая поддержка.

Оригинал: Miss Sister Taste (идентификатор публичной учетной записи WeChat: xjjdog), добро пожаловать, пожалуйста, сохраните источник для перепечатки.

Эта статья начнется с топологии знаний, расскажет о функции API-шлюза и о том, как использовать Spring Cloud Gateway. Статья очень длинная, можно сначала просмотреть оглавление.

一、知识拓扑 (使用和原理)
二、网关的作用
三、Predicate,路由匹配
四、Filter,过滤器编写
五、自定义过滤器
六、常见问题

Почему многие считают, что Spring Cloud Gateway сложен в использовании? потому что он используетwebflux, который включает в себя реактивное программирование, а не традиционное процедурное программирование.

Давайте разберемся в технологии, стоящей за этим.Нетрудно обнаружить, что корень этого неясного происхождения идет от проектного реактора., ориентированная на будущее среда реактивного программирования, которая идет рука об руку с проектом spring.

В результате конечный код совпадает с лямбда.Идея, лежащая в основе этого, представляет собой гибрид режима наблюдателя и неблокирующего режима с относительно крутой кривой обучения..

1. Топология знаний

Spring Cloud Gateway включает в себя много относительно новых знаний и концепций, но только для использования, наклон не очень большой.

1.1 Использование, связанное с

Мы можем представить необходимые элементы маршрута:Веб-запрос с помощью некоторых условий сопоставления находит реальный узел службы. И до и после процесса пересылки, некоторый усовершенствованный контроль.

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

Поскольку Spring Cloud Gateway основан на Springboot, для настройки маршрутизации используется yml. Уровень yml обычно глубокий, из-за чего конфигурационный файл выглядит очень запутанным. Он также может использовать java-код (или kotlin) для написания маршрутизации, а стиль смещен в сторону функционального программирования, поэтому вам нужно сначала понять, как писать лямбда-выражения.

Большую часть времени Spring Cloud Gateway используется в качестве шлюза для http-сервисов, и он может выполнять некоторый детальный контроль http-пакетов, поэтому необходимо лучше понимать HTTP-протокол, чтобы иметь возможность его использовать. легко.

1.2 Связанный принцип

В принципе все гораздо сложнее. Из-за отставания на практике большинство существующих компонентов не догнали «продвинутую» концепцию «отзывчивости», породив кучу непонятных компонентов (в основном слишком много выделенных функций). К счастью, использование Spring Cloud Gateway не требует прямого контакта с этими API.

Самое главное — инкапсулировать фреймворк webflux. Webflux – это набор решений, которые могут заменить Spring MVC. Он может писать адаптивные приложения. Взаимосвязь между ними можно увидеть на рисунке ниже. Он использует netty внизу, поэтому операция является асинхронной и неблокирующей.

Идя дальше, webflux — это оболочка, которая работает поверх реактора проекта, и его основные функции обеспечиваются последним. Это то же самое, что и vert.x, и при первом контакте с ним очень странно работать.

Reactor — это развитие паттерна Observer, поэтому существует концепция Publisher, наиболее важными из которых являются Flux и Mono. Так называемый webflux назван в честь этого.

ссылка на реактор:url.cn/5B7f5iY

Переход от традиционной модели разработки к модели разработки реактора сопряжен с определенными затратами. Если у вас есть время, чтобы понять принцип, лежащий в основе этого, использование Spring Cloud Gateway все еще полезно.

Во-вторых, роль шлюза

Как видно из названия, это сетевой уровень, независимо от того, насколько сложен бэкэнд, производительность внешнего уровня стабильна.

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

Шлюз API — это архитектурный шаблон с появлением концепции микросервисов, и, конечно, он не ограничивается микросервисами. На картинке видно расположение шлюза.

Давайте посмотрим на конкретную роль шлюза ниже.

2.1 Обратный прокси

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

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

2.2 Аутентификация

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

Например, единый доступ по протоколу https, обработка распределенных сессий, доступ к новым каналам аутентификации входа и т. д.

2.3 Управление потоком

Если управление потоком будет распределено на каждый сервис, это будет катастрофа, и шлюз — самое подходящее место.

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

Существует два способа управления потоком: автономное ограничение тока и распределенное ограничение тока.Последний способ управления более совершенен, и Spring Cloud Gateway обеспечивает оба.

2.4 Слияние

Основное различие между автоматическим выключателем и управлением потоком заключается в том, что первая служба «недоступна» в течение определенного периода времени, а вторая — только вероятностно.

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

2.5 Управление оттенками серого

Одной из конечных функций шлюза является реализация публикации сервисов в оттенках серого. Например, часто упоминаемый тест AB — это метод публикации в градациях серого.

Оттенки серого будут точно контролироваться, например, некоторые элементы управления оттенками серого для типа пользователя, определенной физической области, определенного пути запроса, определенного модуля и случайного процента.

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

2.6 Мониторинг журнала

Шлюз — лучшее место для мониторинга журналов. Благодаря подробному анализу журнала доступа можно получить множество ценных данных, которые могут послужить основой для принятия решений по оптимизации внутренних служб.

Например, тенденция доступа «бизнеса», операционные данные, пиковое число запросов в секунду, год к году, месяц к месяцу и т. д.

3. Предикат, сопоставление маршрутов

Есть два способа настроить Spring Cloud Gateway, Fluent API и yml, которые очень хреновые.

Predicate означает утверждение на английском языке. Здесь мы можем думать об этом как об условном сопоставлении, которое может сопоставляться в соответствии с заголовками http или параметрами http.

3.1 Согласование времени

Соответствует до или после определенного момента времени. Например, пусть маршрут действует в течение определенного периода времени.

Файл конфигурации выглядит так:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2020-10-20T17:42:47.789-07:00[America/Denver]

в.idЭто уникальное неповторяющееся имя этого маршрута, uri указывает адрес маршрута после сопоставления, а After of predicates — это наш сопоставитель времени.

1. После

Или перевести в код.

builder.routes().route(
r -> r.after(LocalDateTime.of(2020, 10, 17, 42, 47).atZone(ZoneId.of("America/Denver")))
    .uri("https://example.org")
);

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

2. До

Вышеупомянутое является предыдущим письмом после определенного момента времени, а именно:

Before=2017-01-20T17:42:47.789-07:00[America/Denver]

r.before(LocalDateTime.of(2020, 10, 17, 42, 47).atZone(ZoneId.of("America/Denver")))

3. Междуи в течение определенного периода времени

Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

r.between(
LocalDateTime.of(2020, 10, 17, 42, 47).atZone(ZoneId.of("America/Denver")),
LocalDateTime.of(2027, 10, 17, 42, 47).atZone(ZoneId.of("America/Denver"))
)

3.2 HTTP-информация

Давайте кратко рассмотрим информацию http-запроса, в которой можно сопоставить и контролировать информацию в общих заголовках и заголовках запроса. Для часто используемой информации, такой как Cookie и Host, также была проведена специальная оптимизация. Среди них наиболее часто используются path, cookie, host, query и т. д.

Path

путь является наиболее важным методом сопоставления, можно использовать несколько путей,разделены.

Path=/foo/{segment},/bar/{segment}
r.path("/foo/{segment}","/bar/{segment}")

Обратите внимание, что мы заключаем {segment} в фигурные скобки, и это значение можно получить с помощью кода.

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

String segment = uriVariables.get("segment");

Информация заголовка заголовка

Header=X-Request-Id, \d+
r.header("Header=X-Request-Id", "\\d+")

Подобно файлам cookie, это относится к сопоставлению заголовков http, и здесь можно разместить много информации в оттенках серого или информации о трассировке.

Cookie [header]

Cookie=chocolate, ch.p
r.cookie("chocolate","ch.p")

В информации http есть имя, называемоеchocolateКуки, будь то с обычнымch.pсовпадение.

Информация о хосте [заголовок]Хотя информация о хосте также находится в информации заголовка, поскольку она очень часто используется, существует специальный сопоставитель.

Host=**.somehost.org,**.anotherhost.org
r.host("Host=**.somehost.org","**.anotherhost.org")

Обратите внимание, что совпадающая строка здесь в стиле Ant, что является более кратким, а не регулярным выражением в java. Использование нескольких хостов,разделять.

Request Method

Method=GET
r.method("GET")

Обратите внимание, я не нашел код в случае преобразования исходного кода, поэтому не забудьте сохранить маршрут в верхнем регистре. В дополнение к CONNECT поддерживаются.

Query

Это относится к строке параметров после вопросительного знака URL.

Query=baz
r.query("baz")

Query=foo, ba.
r.query("foo","ba.")

Это настолько просто, что мне не нужно представление.

RemoteAddr

 RemoteAddr=192.168.1.1/24
 r->r.remoteAddr("192.168.1.1/24")

3.3 Вес

Конфигурация информации о весе - это бит 2b. Например, у нас за спиной два сервера, и Spring Cloud Gateway сделал для них два маршрута, хабом ссылки является ссылка с именемWeightгруппа.

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

Тот же код ниже.

builder.routes()
.route("weight_high",r -> r.weight("group1", 8).uri("https://weighthigh.org"))
.route("weight_low",r -> r.weight("group1", 2).uri("https://weightlow.org"));

Если в сервисе 100 узлов и куча фильтров, нужно ли повторять настройку 100 раз? Должен сказать, очень хреново.

В-четвертых, фильтр, фильтр записи

Сопоставление может найти маршрут для проксирования. Теперь мы вошли внутрь нашей маршрутизации. Здесь настраивается большинство функций упомянутой выше маршрутизации.

Те, кто использовал шлюз zuul, могут знать, что при пользовательской маршрутизации будут две аннотации, до и после, для управления поведением маршрутизации до и после прокси. Spring Cloud Gateway имеет тот же эффект.

4.1 Модификация информации

Хрень существует не только в SSM, но и в настройке роутинга. Вы можете изменить заголовки http или другую информацию перед маршрутизацией к реальной серверной службе или внести некоторые изменения после проксирования соответствующей ссылки.

В нашем понимании так называемый запрос соответствует pre, а ответ соответствует post.

AddRequestHeader=X-Request-Foo, Bar
AddRequestParameter=foo, bar
AddResponseHeader=X-Response-Foo, Bar

RemoveRequestHeader=X-Request-Foo
RemoveResponseHeader=X-Response-Foo
RemoveRequestParameter=foo

SetRequestHeader=X-Request-Foo, Bar
SetResponseHeader=X-Response-Foo, Bar

SetStatus=401

4.2 Модификация тела запроса

Это немного больно, причина все же вызвана webflux, и это более индивидуально в написании.

.filters(f -> f.modifyRequestBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE,
    (exchange, s) -> {
            return Mono.just(s.toUpperCase());
})

Приведенный выше код преобразует все содержимое requestBody в верхний регистр.

Точно так же ответ соответствует модификации ResponseBody, и его запись аналогична. Подробнее см. ModifyRequestBodyGatewayFilterFactory код. Если вы не касались упомянутой выше теоретической части, читать ее все равно довольно сложно.

4.3 Перенаправление

RedirectTo=302, https://acme.org

.filters(f -> f.redirect(302,"https://acme.org"))

перенаправить напрямую. Это относительно просто, не вдаваясь в слишком много введения.

4.4 Удалить префикс

фокус.

StripPrefix=2

.filters(f->f.stripPrefix(2))

StripPrefix может принимать неотрицательное целое число для удаления соответствующего префикса. Например, путь для внешнего доступа/a/b/c/dЗатем путь к серверной службе/c/d,Избавиться/a/bпрефикс.

Это особый способ перезаписи пути, обычно используемый для uri.lb://Путь микросервиса переписан для протокола.

4.5 Перезапись пути

RewritePath очень похож на перезапись пути nginx.

RewritePath=/foo(?<segment>/?.*), $\{segment}

f.rewritePath("/foo(?<segment>/?.*)", "${segment}")

Официальный сказал, из-за файла конфигурации yml. положить$написано как$\способ, но это не требуется в java-коде. Поскольку внутреннее использование java по-прежнему является регулярным, и в то же время используется понятие группы, код действительно грязный.

4.6 Конфигурация фьюзинга

Встроенным автоматическим выключателем по умолчанию по-прежнему является hystrix.

Hystrix=myCommandName

.filters(f -> f.hystrix(c->c.setName("myCommandName")))

Кроме того, предохранитель имеет параметр, называемыйfallbackUri, но, к сожалению, поддерживается только прямой метод. Например:

fallbackUri: forward:/myfallback

4.7 Повторите настройку

Для некоторых служб, требующих очень высокой стабильности, неизбежной проблемой является повторная попытка. Есть много параметров для повторной попытки. Типичная конфигурация выглядит следующим образом:

- name: Retry
    args:
        retries: 3
        statuses: BAD_GATEWAY
        backoff:
            firstBackoff: 10ms
            maxBackoff: 50ms
            factor: 2
            basedOnPreviousValue: false

Среди них отсрочка указывает стратегию повторных попыток и интервал, которые будут следовать формулеfirstBackoff * (factor ^ n)расти.

Автоматический выключатель обеспечивает безопасность службы, а повторная попытка обеспечивает надежность службы.Обратите внимание на проверку сценариев использования.

4.8 Ограничение тока

Встроенный ограничитель тока при срабатывании возвращает ошибку «HTTP 429 — слишком много запросов».

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

public interface KeyResolver {
    Mono<String> resolve(ServerWebExchange exchange);
}

В то же время распределенное ограничение тока на основе принципа Token Bucket в Redis. Поскольку нижний уровень использует «spring-boot-starter-data-redis-reactive», он имеет характеристики «отзывчивого» приложения и поддерживает обратное давление WebFlux (Reactor). По настройке есть некоторые навороты, например официальная конфигурация.

- name: RequestRateLimiter
    args:
        key-resolver: '#{@ipKeyResolver}'
        redis-rate-limiter.replenishRate: 10
        redis-rate-limiter.burstCapacity: 20

Нам нужно имя, называемоеipKeyResolverбоб.

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

5. Пользовательские фильтры

Фильтр весеннего облачного шлюза разделен на глобальный фильтр и локальный фильтр, и соответствующий интерфейсGatewayFilterиGlobalFilter.

Если встроенный фильтр не соответствует вашим потребностям, вы можете решить эту проблему с помощью пользовательского фильтра. путем реализацииGatewayFilterиOrderedинтерфейс для более гибкого управления.

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

6. Часто задаваемые вопросы

Что означает lb://?

lb://serviceName — это uri балансировки нагрузки, который Spring Cloud Gateway автоматически создает для нас в микросервисах, В некоторых особых случаях его можно написать напрямую. Например, если зарегистрированное имя в eureka — pay-rpc, то оно записывается так:

lb://pay-rpc

Как изменить содержимое http? Например, метод?

Обратите внимание на эту вещь ServerWebExchange. используй это Функция exchange.mutate() может войти в режим модификации. Например, чтобы преобразовать метод GET в POST:

ServerHttpRequest request = exchange.getRequest();
if (request.getMethod() == HttpMethod.GET) {
    exchange = exchange.mutate().request(request.mutate().method(HttpMethod.POST).build()).build();
}

Как динамически обновлять маршруты?В основном через интерфейс управления приводом, чтобы убедиться, что это содержимое размещено во внутренней сети.

GET /actuator/gateway/routes 路由列表
GET  /actuator/gateway/routes/{id} 获取某个路由信息
GET /actuator/gateway/globalfilters 全局过滤器
GET /actuator/gateway/routefilters filter列表
POST /actuator/gateway/refresh 刷新路由
POST /gateway/routes/{id_route_to_create} 创建路由
DELETE /gateway/routes/{id_route_to_delete}  删除某个路由

Как сделать немного статистики

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

Ни то, ни другое не сложно, и в основном речь идет о планировании функциональности, а не кода.

У меня есть более сложные функции, такие как необходимость расшифровки данных, как мне это сделать?

Это реализовать фильтр самостоятельно.

 Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

Через ServerWebExchange вы можете управлять добавлением, изменением, удалением, перезаписью и т. д. любого параметра во всем процессе запроса. До и после метода прокси можно пройти

exchange.getAttributes().put();
exchange.getAttribute()

Эти две функции для передачи параметров

Поэтому, даже если официалы не пишут ни одного из вышеупомянутых фильтров, мы все равно можем использовать этот базовый интерфейс для игры.

End

Публичная учетная запись WeChat действительно не подходит для написания некоторых обучающих статей, поэтому эта статья все еще является кратким опытом.

С изъятием zuul1 и дистоцией zuul2 лучшим выбором стал биологический SCG. Команда Spring очень интересная, она напрямую внедряет webflux в качестве back-end технологии (страх перед изменениями?), от чего многие люди страдают: им приходится заново осваивать новые технологии.

В этой статье не тестируется производительность SCG, которая была проверена многими командами и дает хорошие результаты.

Но с текущим облачным шлюзом spring по-прежнему много проблем. К счастью, эта проблема связана с использованием, а не с функциональной проблемой. Он имеет множество встроенных предикатов и фильтров, но во многих случаях он не может решить проблему, и пользователям приходится создавать свои собственные фильтры. Ну, большинство моих фильтров самодельные.

Кроме того, я жалуюсь на конфигурацию Fluent API и yml, это действительно некрасиво, и необходимо разработать фон управления. Есть также сложные обычные вещи Java, которые сводят людей с ума - посмотрите на эти глубокие следы от когтей на стене, это мой шедевр.

Об авторе:Мисс сестра вкус(xjjdog), публичная учетная запись, которая не позволяет программистам идти в обход. Сосредоточьтесь на инфраструктуре и Linux. Десять лет архитектуры, десятки миллиардов ежедневного трафика, обсуждение с вами мира высокой параллелизма, дающие вам другой вкус. Мой личный WeChat xjjdog0, добро пожаловать в друзья для дальнейшего общения.​