Шлюз микросервиса netflix-zuul

задняя часть Микросервисы Spring API

Введение: предыдущая серия статей представленаПроектирование и реализация аутентификации и управления разрешениями API в микросервисной архитектуре, Многие студенты спрашивали, есть ли готовый демонстрационный проект, и автор ответил утвердительно. Так как предыдущая серия статей была посвящена преавторизации, в ближайшее время будет добавлен полный постпроект, но лучше всего иметь полный вызов микросервиса. В этой статье в основном рассказывается о разработке и реализации шлюза API. netflix-zuul — это шлюз API с открытым исходным кодом от netflix.В рамках микросервисной архитектуры шлюз действует как внешний портал для реализации таких функций, как динамическая маршрутизация, мониторинг, авторизация, безопасность и планирование.

1. Введение в шлюз

При использовании монолитной архитектуры приложения мобильный клиент будет извлекать эти данные, выполняя вызов REST к приложению. Балансировщик нагрузки направляет запросы к одному из N идентичных экземпляров приложения. Затем приложение запрашивает различные таблицы базы данных и возвращает ответы клиенту. В микросервисной архитектуре одно приложение разделено на несколько микросервисов, и если все микросервисы открыты напрямую, неизбежно возникнут различные проблемы с безопасностью.
Клиент может отправлять запросы напрямую к каждому микросервису, и основные проблемы заключаются в следующем:

  • Одной из проблем является несоответствие между требованиями клиента и детализированным API, предоставляемым каждой микрослужбой.
  • Еще одна проблема с клиентами, вызывающими микросервисы напрямую, заключается в том, что некоторые сервисы используют протоколы, которые не подходят для Интернета. Одна служба может использовать двоичный RPC Thrift, а другая может использовать протокол обмена сообщениями AMQP. Ни один из протоколов не является дружественным к браузеру или брандмауэру, и их лучше всего использовать внутри. За пределами брандмауэра приложения должны использовать такие протоколы, как HTTP и WebSocket.
  • В конце концов, это затрудняет рефакторинг микросервисов. Со временем мы можем захотеть изменить способ разделения системы на службы. Например, мы можем объединить две службы или разделить одну службу на две или более служб. Однако, если клиент взаимодействует напрямую с микросервисом, выполнить такой тип рефакторинга очень сложно.

Лучшим подходом является использование так называемого шлюза API. Шлюз API — это сервер и единственная точка входа в систему. С точки зрения объектно-ориентированного проектирования он похож на шаблон Facade. Шлюз API инкапсулирует внутреннюю архитектуру системы и предоставляет настраиваемый API для каждого клиента. У него также могут быть другие обязанности, такие как аутентификация, мониторинг, балансировка нагрузки, регулирование, деградация и обнаружение приложений.

zu

zuul

Шлюз API отвечает за маршрутизацию запросов на обслуживание, композицию и преобразование протоколов. Все запросы от клиента сначала проходят через шлюз API, который затем направляет запрос в соответствующий микросервис. Веб-мастера API часто обрабатывают запрос, вызывая несколько микросервисов и объединяя результаты. Он может конвертировать между веб-протоколами, такими как HTTP и WebSocket, и внутренними протоколами, не дружественными к Интернету.

Шлюз API также может предоставить каждому клиенту собственный API. Как правило, он предоставляет мобильным клиентам приблизительный API. Например, рассмотрим сценарий листинга продуктов. Шлюз API может предоставить конечную точку (/productdetails?productid=xxx), которая позволяет мобильным клиентам получать все сведения о продукте одним запросом. Шлюз API обрабатывает запросы, вызывая отдельные службы (информация о продукте, рекомендации, обзоры и т. д.) и объединяя результаты.

2. зуул шлюз

API Gateway, распространенными вариантами являются Kong на основе Openresty и Zuul на основе JVM, а другие — Tyk на основе Go. С точки зрения технического выбора, я исследовал Kong немного раньше, и производительность в порядке. Учитывая быстрое применение и вторичную разработку, netflix-zuul также находится в корзине семейства Spring Cloud, и его достаточно удобно использовать с другими компонентами.Функция шлюза может быть расширена позже, и окончательно выбран Zuul.

2.1 пом конфигурация

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>
</dependencies>

В проекте Spring Cloud введены zuul's starter и consul-discovery для динамической маршрутизации сервисов, здесь не используется Eureka, а маршрутизация осуществляется через экземпляры сервисов, зарегистрированных на консуле.

2.2 Начальный класс

@SpringBootApplication
@EnableZuulProxy
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

Необходимо добавить начальный класс загрузки Spring.@EnableZuulProxy, см. это примечание ниже.

@EnableCircuitBreaker
@EnableDiscoveryClient
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({ZuulProxyConfiguration.class})
public @interface EnableZuulProxy {
}

Видно, что аннотация также содержит@EnableCircuitBreaker 和 @EnableDiscoveryClient.@EnableDiscoveryClientПри запуске аннотации процесс регистрации службы может быть запущен в центр регистрации службы, указанный в файле конфигурации;@EnableCircuitBreakerЗатем включается автоматический выключатель Hystrix.

2.3 bootstrap.yml

server:
  port: 10101
    
#spring config
spring:
  application:
    name: gateway-server
  cloud:
    consul:
      discovery:
        preferIpAddress: true
        enabled: true
        register: true
        service-name: api-getway
        ip-address: localhost
        port: ${server.port}
        lifecycle:
          enabled: true
        scheme: http
        prefer-agent-address: false
      host: localhost
      port: 8500
#zuul config and routes
zuul:
  host:
    maxTotalConnections: 500
    maxPerRouteConnections: 50
  routes:
    user:
      path: /user/**
      ignoredPatterns: /consul
      serviceId: user
      sensitiveHeaders: Cookie,Set-Cookie

Конфигурация в основном включает три части: порт службы, регистрацию службы Spring Cloud и, наконец, конфигурацию маршрутизации zuul.

По умолчанию Zuul будет фильтровать некоторую конфиденциальную информацию в информации заголовка HTTP-запроса при запросе маршрутизации.Конфиденциальная информация заголовка по умолчанию определяется zuul.sensitiveHeaders, включая Cookie, Set-Cookie и Authorization.

zuul.host.maxTotalConnections настраивает максимальное количество подключений пула HTTP-клиентов для каждой службы. Значение по умолчанию — 200. maxPerRouteConnections Максимальное количество подключений, доступных на маршрут, значение по умолчанию — 20.

2.3 Поддержка https

Как правило, доменное имя онлайн-проекта будет изменено на протокол https, а конфигурация https будет записана.

  • Сначала подайте заявку на цифровой сертификат для https
    После успешного применения сертификата ЦС, созданного Alibaba Cloud для сервера tomcat, загрузите соответствующий файл сертификата tomcat. Содержит следующее:
    1): .pfx — это файл хранилища ключей, сервер использует этот файл
    2): pfx-password.txt содержит пароль, используемый хранилищем ключей
    3): .key содержит закрытый ключ, этот файл пока не используется
    4): *.pem содержит открытый ключ, в основном для клиента

  • Bootstrap.yml добавляет следующую конфигурацию

# https
server:
  port: 5443
  http: 10101
  ssl:
    enabled: true
    key-store: classpath:214329585620980.pfx
    key-store-password: password
    keyStoreType: PKCS12
  • Поддержка как http, так и https
@Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint constraint = new SecurityConstraint();
                constraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("");
                constraint.addCollection(collection);
                context.addConstraint(constraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }
    @Bean
    public Connector httpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        //Connector监听的http的端口号
        connector.setPort(httpPort);
        connector.setSecure(false);
        //监听到http的端口号后转向到的https的端口号
        connector.setRedirectPort(securePort);
        return connector;
    }

servletContainer()ПучокEmbeddedServletContainerFactoryВнедрить в веб-контейнер, использоватьpostProcessContextПерехватите все запросы /* и свяжите их с приведенным ниже httpConnector. Наконец, в httpConnector() установите http на порт 10101 и перенаправьте HTTP-запрос на https-порт 5443, вот файл конфигурации для чтения.

На данный момент шлюз API, поддерживающий как https, так и http, завершен, и очень просто направлять запросы, соответствующие /user, в пользовательский сервис? Давайте подробнее рассмотрим Зуула.

3. Немного внутренностей

Интерналов можно понимать как инсайдеров.

3.1 Фильтры

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

filter

зуул фильтр

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

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

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

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

3.2 Управление конфигурацией

В зависимости от ситуации API внутренней службы может не требовать подтверждения входа. Как можно динамически загрузить эту информацию о конфигурации в конфигурацию шлюза? Автор считает, что есть два пути: один — хранить информацию о конфигурации в библиотеке и периодически обновлять конфигурацию службы шлюза; другой — инициировать горячее обновление службы шлюза на основе службы центра конфигурации, когда конфигурация отправляется в центр конфигурации.

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

3.3 Механизм изоляции

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

Это, конечно, возможно.Представьте себе приложение, которое принимает много запросов в секунду.В нормальных условиях на эти запросы можно нормально ответить в течение 10 миллисекунд, но если однажды что-то пойдет не так, все запросы будут заблокированы до 30. Это будет только отключается по тайм-ауту в несколько секунд (например, частый полный сборщик мусора не может эффективно освободить память). В это время в шлюзе также будет большое количество потоков, ожидающих ответа на запрос, что в итоге съест все потоки, что также повлияет на запросы других обычных приложений.

В Zuul каждое внутреннее приложение называется Route.Чтобы избежать ситуации, когда Route занимает слишком много ресурсов и влияет на другие Route, Zuul использует Hystrix для изоляции и ограничения потока каждого Route.

В Hystrix есть две стратегии изоляции: на основе потоков и на основе семафоров. По умолчанию в Zuul используется механизм изоляции на основе потоков.Конфигурация, описанная в предыдущих главах, может быть пересмотрена, что означает, что каждый запрос Route будет выполняться в независимом пуле потоков фиксированного размера, так что даже в случае возникновения проблемы с одним из Маршруты, только определенный пул потоков будет заблокирован, а другие маршруты не будут затронуты.

Как правило, при использовании Hystrix семафор используется для стратегии изоляции только тогда, когда количество вызовов огромно и на них будут влиять накладные расходы потока.Более безопасно использовать изоляцию потока для сетевых запросов, таких как Zuul.

3.4 Механизм повтора

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

Кратко опишите, какие отказоустойчивые конфигурации поддерживает Ribbon. Существует три сценария повтора:

  • okToRetryOnConnectErrors: повторите попытку только при сетевых ошибках.
  • okToRetryOnAllErrors: повторить все ошибки
  • OkToRetryOnAllOperations: повторить все операции

Существует два типа повторных попыток:

  • MaxAutoRetries: максимальное количество повторных попыток на узел.
  • MaxAutoRetriesNextServer: максимальное количество попыток замены узла.

Вообще говоря, мы хотим повторять попытку только в случае сбоя сетевого подключения или повторять запросы 5XX GET (не рекомендуется повторять запросы POST, и нельзя гарантировать, что идемпотентность вызовет несогласованность данных). Количество повторных попыток для одного блока может быть как можно меньше, а количество узлов повторных попыток может быть как можно больше, и общий эффект будет лучше.

Если есть более сложные сценарии повторных попыток, такие как необходимость повторной попытки определенных API и определенных возвращаемых значений, вы также можете настроить логику, реализовав RequestSpecificRetryHandler (не рекомендуется использовать RetryHandler напрямую, поскольку этот подкласс может использовать многие существующие функции).

4. Резюме

Эта статья, во-первых, знакомит с соответствующими знаниями об API-шлюзе; во-вторых, в ней рассказывается о настройке и реализации zuul-шлюза, который поддерживает https; наконец, в ней вводятся некоторые внутренние принципы zuul-шлюза, и большинство статей в Интернете упоминаются здесь. . Шлюз выступает в роли портала между внутренней сетью и внешней сетью, все запросы на доступ во внутреннюю сеть будут проходить через шлюз, а шлюз будет выполнять обратное проксирование. Во всей микросервисной среде Spring Cloud Zuul играет роль «умного шлюза».

gitee: git ee.com/can ets/judgment day you…
github: GitHub.com/Доступный ETS2012/S…


Ссылаться на

  1. Разговор об API Gateway и Netflix Zuul
  2. Технический анализ Spring Cloud (4) - spring cloud zuul
  3. netflix-zuul