sbc (шесть) Приложение шлюза Zuul GateWay

задняя часть Микросервисы API Эксплуатация и обслуживание

предисловие

видел раньшеSBCНебольшие партнеры в этой серии должны иметь возможность создавать высокодоступные и распределенные микросервисы. Текущая структурная схема должна выглядеть так:

Между различными микросервисами нет единой точки, и все они зарегистрированы вEureka, на основании которого сервис регистрируется и обнаруживается, а затем передаетсяRibbonСовершает сервисные вызовы и имеет возможности загрузки клиентов.

Все выглядит хорошо, но вот одна важная деталь, которую я забыл:

Что мы должны делать, когда нам нужно предоставлять внешние услуги?

Конечно, этого тоже можно добиться, это не что иное, как раскрытие нашего конкретного адреса и порта микросервиса.

Тогда как добиться нагрузки?

Простой! в состоянии пройтиNginx F5инструменты, такие как нагрузка.

Но если система огромна и сервисы достаточно разделены, кто будет поддерживать эти отношения маршрутизации?

Конечно, это работа по эксплуатации и техническому обслуживанию, но в это время эксплуатация и техническое обслуживание могут вот-вот сойти с ума!

И есть ряд вопросов:

  • Как выполнить аутентификацию и проверку подписи между вызовами службы?
  • Из-за большого количества адресов серверов запросы клиентов трудно поддерживать.

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

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

Он также имеет следующие функции:

  • Зуул зарегистрирован вEurekaи интегрированныйRibbonПоэтому, естественно, список сервисов можно получить из реестра для клиентской нагрузки.
  • Многофункциональные функции маршрутизации разгружают O&M.
  • С помощью фильтров можно интегрировать аутентификацию и проверку подписи.

Исходя из этого, давайте посмотрим, как интегрироваться в предыдущую архитектуру.Zuul.

Интегрировать Зуул

Для этого я создал проект.sbc-gateway-zuulявляется основнымSpringBootструктура. Он добавляет зависимости Zuul:

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

Поскольку шлюз должен быть зарегистрирован вEureka, поэтому, естественно, также требуется:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

Затем настройте некоторую базовую информацию о проекте:

# 项目配置
spring.application.name=sbc-gateway-zuul
server.context-path=/
server.port=8383

# eureka地址
eureka.client.serviceUrl.defaultZone=http://node1:8888/eureka/
eureka.instance.prefer-ip-address=true

Добавить enable в класс запускаZuulОбратите внимание, что приложение шлюза настроено.

@SpringBootApplication

//开启zuul代理
@EnableZuulProxy
public class SbcGateWayZuulApplication {
}

запускатьEurekaИ шлюз видит, что регистрация прошла успешно и все готово:

сервисная маршрутизация

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

традиционная маршрутизация

Традиционная маршрутизация очень проста иNginxТочно так же разработчики, эксплуатационный и обслуживающий персонал поддерживают отношения сопоставления между адресами запросов и соответствующими службами, подобно:

zuul.routes.user-service.path=/user-service/**
zuul.routes.user-sercice.url=http://localhost:8080/

поэтому, когда мы посещаемhttp://localhost:8383/user-service/getUserInfo/1Шлюз автоматически направит нас кhttp://localhost:8080/getUserInfo/1начальство.

Можно видеть, что пока мы поддерживаем это отношение отображения, мы можем свободно настраивать информацию о маршрутизации (user-sercice 可自定义), но очевидно, что этот метод не удобен для эксплуатации и обслуживания или разработки. Так как этот метод мало используется на практике, я буду расширять его дальше.

сервисная маршрутизация

к этомуZuulПредоставляет метод маршрутизации на основе службы. Нам нужно только поддерживать отношение сопоставления между адресом запроса и идентификатором службы, и из-за интегрированногоRibbon, Zuul также может реализовать вызовы загрузки через Eureka при маршрутизации.

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

zuul.routes.sbc-user.path=/api/user/**
zuul.routes.sbc-user.serviceId=sbc-user

поэтому, когда вводhttp://localhost:8383/api/user/getUserInfo/1будет перенаправлен на регистрациюEurekaИдентификатор среднего сервиса:sbc-userСервисный узел, если он состоит из нескольких узлов, следует одному из алгоритмов загрузки ленты.

Вышеупомянутая конфигурация также может быть сокращена как:

# 服务路由 简化配置
zuul.routes.sbc-user=/api/user/**

Это дает нам доступhttp://127.0.0.1:8383/api/user/userService/getUserByHystrixНа данный момент это поможет нам выполнить маршрутизацию к приложению sbc-user в соответствии с алгоритмом загрузки, как показано на следующем рисунке:


Запустил две службы sbc-user.

Результат запроса:

Одна маршрутизация завершена.

Видел в конфигурации выше/api/user/**Для такой конфигурации с подстановочными знаками необходимо понимать три конкретных конфигурации:

  • ?может соответствовать только одному символу, например/api/user/?просто соответствовать/api/user/x /api/user/y /api/user/zтакой путь.
  • *может соответствовать только любому символу, например/api/user/*просто соответствовать/api/user/x /api/user/xy /api/user/xyz.
  • **Может соответствовать любому персонажу, любого уровня. Сочетает в себе характеристики двух вышеуказанных подстановочных знаков, таких как/api/user/**может соответствовать/api/user/x /api/user/x/y /api/user/x/y/zzzТакой путь самый простой и самый грубый!

Когда дело доходит до сопоставления с подстановочными знаками, мы должны упомянуть о проблеме, такой как приведенная выше.sbc-userИз-за более позднего итеративного обновления службы часть логики в sbc-user извлекается в другую службу.sbc-user-pro. Недавно примененное правило маршрутизации/api/user/pro/**, если мы следуем:

zuul.routes.sbc-user=/api/user/**
zuul.routes.sbc-user-pro=/api/user/pro/**

Для настройки мы хотим передать/api/user/pro/посетитьsbc-user-proприложение, но оно будет перенаправлено Zuul, поскольку оно удовлетворяет первому правилу маршрутизации.sbc-userВ данном приложении это явно неправильно. Как решить эту проблему?

Посмотрите исходный код маршрутизацииorg.springframework.cloud.netflix.zuul.filters.SimpleRouteLocatorсерединаlocateRoutes()метод:

    /**
     * Compute a map of path pattern to route. The default is just a static map from the
     * {@link ZuulProperties}, but subclasses can add dynamic calculations.
     */
    protected Map<String, ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>();
        for (ZuulRoute route : this.properties.getRoutes().values()) {
            routesMap.put(route.getPath(), route);
        }
        return routesMap;
    }

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

фильтр

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

Выдержка из официального объяснения: Ядром Zuul является серия фильтров, которые могутHTTPВ процессе запроса и ответа выполняются различные операции.

На самом деле его можно свести к четырем характеристикам:

  • тип фильтра
  • порядок фильтрации
  • условие выполнения
  • Реализация

На самом деле этоZuulFilterЧетыре интерфейса, определенные в интерфейсах:

String filterType();

int filterOrder();

boolean shouldFilter();

Object run();

Официальная блок-схема (жизненный цикл):

Простое понимание:

Когда приходит запрос, он идет первымpreФильтр, может выполнять некоторую аутентификацию, записывать журнал отладки и другие операции. войти послеroutingФильтр для переадресации маршрутизации, переадресация может использоватьApache HttpClientилиRibbon.
postФильтр предназначен для обработки данных после ответа службы, и можно выполнить некоторую упаковку, чтобы вернуть их клиенту.errorОн вызывается при возникновении исключения, что эквивалентно глобальному перехватчику исключений.

пользовательский фильтр

Далее реализуем операцию аутентификации, упомянутую в начале статьи:

создать новыйRequestFilterнаследование классов иZuulFilterинтерфейс

/**
 * Function: 请求拦截
 *
 * @author crossoverJie
 *         Date: 2017/11/20 00:33
 * @since JDK 1.8
 */
public class RequestFilter extends ZuulFilter {
    private Logger logger = LoggerFactory.getLogger(RequestFilter.class) ;
    /**
     * 请求路由之前被拦截 实现 pre 拦截器
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {

        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String token = request.getParameter("token");
        if (StringUtil.isEmpty(token)){
            logger.warn("need token");
            //过滤请求
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(400);
            return null ;
        }
        logger.info("token ={}",token) ;

        return null;
    }
}

Очень просто, включено ли оно в запрос простой проверкиtoken, код 401, если он не включен.

Не только это, но вам также нужно добавить этот класс в Spring для управления:

новыйFilterConfДобрый:

@Configuration
@Component
public class FilterConf {

    @Bean
    public RequestFilter filter(){
        return  new RequestFilter() ;
    }
}

После перезапуска таким образом вы можете увидеть эффект:

Когда токен не передается:

Входящий токен:

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

Остальные фильтры аналогичны и могут быть настроены в соответствии с реальной сценой.

Зуул высокая доступность

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

Эврика Высокая доступность

Первый проще всего придумать и реализовать:
Мы можем развернуть несколько узлов Zuul, и все они зарегистрированы в Eureka, как показано ниже:

Хотя это просто и легко поддерживать, у него есть серьезный недостаток: клиент также должен зарегистрироваться в Eureka для загрузки вызовов Zuul, что явно нереально.

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

Высокая доступность на основе Nginx

Используйте инструмент балансировки нагрузки, такой как Nginx, для загрузки перед вызовом Zuul, чтобы Zuul мог не только зарегистрироваться в Eureka, но и клиент мог загрузить Zuul, как показано на следующем рисунке:

Суммировать

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

проект:GitHub.com/crossover J я…

Блог:crossoverjie.top.