1. Обзор
Zuul — это пограничный сервис (или шлюз API) от Netflix, который обеспечивает динамическую маршрутизацию, мониторинг, отказоустойчивость и безопасность.
В этом туториале мы рассмотрим, как настроить маршруты Zuul с резервными вариантами .
2. Первоначальная настройка
Для начала мы сначала настроим два приложения Spring Boot. В первом приложении мы создадим простую службу REST. Принимая во внимание, что во втором приложении мы будем использовать прокси-сервер Zuul для создания маршрута для службы REST первого приложения.
2.1. Простой REST-сервис
Допустим, нашему приложению необходимо отобразить пользователю сегодняшнюю информацию о погоде. Итак, мы создадим приложение службы погоды на основе Spring Boot, используя стартер spring-boot-starter-web
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Теперь мы создадим контроллер для нашего погодного сервиса:
@RestController
@RequestMapping("/weather")
public class WeatherController {
@GetMapping("/today")
public String getMessage() {
return "It's a bright sunny day today!";
}
}
Теперь давайте запустим службу погоды и проверим API службы погоды:
$ curl -s localhost:8080/weather/today
It's a bright sunny day today!
2.2. Приложение шлюза API
Давайте теперь создадим наше второе приложение Spring Boot, шлюз API. В этом приложении мы создадим маршрут Zuul для нашей службы погоды.
И поскольку и наша служба погоды, и Zuul по умолчанию захотят использовать 8080, мы настроим его для работы на другом порту, 7070.
Итак, давайте сначала добавим spring-cloud-starter-netflix-zuul
в pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
Далее мы добавим аннотацию @EnableZuulProxy
в наш класс приложения API Gateway:
@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
Наконец, мы настроим маршрут Zuul, используя ленту, для нашего API службы погоды в application.yml
:
spring:
application:
name: api-gateway
server:
port: 7070
zuul:
igoredServices: '*'
routes:
weather-service:
path: /weather/**
serviceId: weather-service
strip-prefix: false
ribbon:
eureka:
enabled: false
weather-service:
ribbon:
listOfServers: localhost:8080
2.3. Тестирование зуульского маршрута
На данный момент оба приложения Spring Boot настроены на предоставление API службы погоды с использованием прокси-сервера Zuul.
Итак, запустим оба приложения и проверим API погодного сервиса через Zuul:
$ curl -s localhost:7070/weather/today
It's a bright sunny day today!
2.4. Тестирование сбоя маршрута Zuul без отката
Теперь давайте остановим приложение службы погоды и снова проверим службу погоды через Zuul. В результате в ответе мы увидим сообщение об ошибке:
$ curl -s localhost:7070/weather/today
{"timestamp":"2019-10-08T12:42:09.479+0000","status":500,
"error":"Internal Server Error","message":"GENERAL"}
Очевидно, это не тот ответ, который хотел бы видеть пользователь. Итак, один из способов позаботиться об этом — создать запасной вариант для маршрута метеослужбы Zuul.
3. Zuul Fallback для маршрута
Прокси-сервер Zuul использует ленту для балансировки нагрузки, а запросы выполняются в команде Hystrix. В результате в матрице Hystrix появляются сбои на зуульском маршруте .
Поэтому, чтобы создать настраиваемый запасной вариант для маршрута Zuul, мы создадим bean-компонент типа FallbackProvider
.
3.1. Класс WeatherServiceFallback
_
В этом примере мы хотим вернуть сообщение из резервного ответа вместо сообщения об ошибке по умолчанию, которое мы видели ранее. Итак, давайте создадим простую реализацию FallbackProvider
для маршрута службы погоды:
@Component
class WeatherServiceFallback implements FallbackProvider {
private static final String DEFAULT_MESSAGE = "Weather information is not available.";
@Override
public String getRoute() {
return "weather-service";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
if (cause instanceof HystrixTimeoutException) {
return new GatewayClientResponse(HttpStatus.GATEWAY_TIMEOUT, DEFAULT_MESSAGE);
} else {
return new GatewayClientResponse(HttpStatus.INTERNAL_SERVER_ERROR, DEFAULT_MESSAGE);
}
}
}
Как мы видим, мы переопределили методы getRoute
и fallbackResponse
. Метод getRoute
возвращает идентификатор
маршрута, для которого мы должны создать запасной вариант. Принимая во внимание, что метод fallbackResponse
возвращает настраиваемый резервный ответ , объект типа GatewayClientResponse
в нашем случае. GatewayClientResponse — это
простая реализация ClientHttpResponse
.
3.2. Тестирование Zuul Fallback
Теперь давайте проверим резервную копию, которую мы создали для службы погоды. Поэтому мы запустим приложение API Gateway и убедимся, что приложение службы погоды остановлено.
Теперь давайте получим доступ к API службы погоды через маршрут Zuul и посмотрим на резервный ответ в действии:
$ curl -s localhost:7070/weather/today
Weather information is not available.
4. Резервный вариант для всех маршрутов
До сих пор мы видели, как создать запасной вариант для маршрута Zuul, используя его идентификатор
маршрута . Однако предположим, что мы также хотим создать общий запасной вариант для всех других маршрутов в нашем приложении. Мы можем сделать это, создав еще одну реализацию FallbackProvider
и вернув *
или null
из метода getRoute
вместо идентификатора
маршрута :
@Override
public String getRoute() {
return "*"; // or return null;
}
5. Вывод
В этом уроке мы видели пример создания резервного варианта для маршрута Zuul. Мы также увидели, как можно создать общий запасной вариант для всех маршрутов Zuul.
Как обычно, реализацию всех этих примеров и фрагментов кода можно найти на GitHub .