предисловие
видел раньше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.