1. Обзор
В этом руководстве мы представим обнаружение сервисов на стороне клиента через «
Spring Cloud Netflix Eureka.
”
Обнаружение служб на стороне клиента
позволяет службам находить друг друга и связываться друг с другом без жесткого кодирования имени хоста и порта. Единственной «фиксированной точкой» в такой архитектуре является реестр служб,
в котором должна регистрироваться каждая служба.
Одним из недостатков является то, что все клиенты должны реализовать определенную логику для взаимодействия с этой фиксированной точкой. Это предполагает дополнительный сетевой цикл до фактического запроса.
С Netflix Eureka каждый клиент может одновременно действовать как сервер, чтобы реплицировать свой статус подключенному узлу. Другими словами, клиент извлекает список всех подключенных одноранговых узлов в реестре служб
и отправляет все дальнейшие запросы к другим службам с помощью алгоритма балансировки нагрузки.
Чтобы быть проинформированным о присутствии клиента, они должны отправить в реестр сигнал сердцебиения.
Для достижения цели этого руководства мы реализуем три микросервиса
:
сервисный реестр
(Eureka
Server )- служба
REST
, которая регистрируется в реестре (Eureka Client
) - веб-приложение, которое использует службу
REST
в качестве клиента с поддержкой реестра (клиентSpring Cloud Netflix Feign
)
2. Сервер Эврика
Внедрить Eureka Server
для сервисного реестра так же просто, как:
- добавление
spring-cloud-starter-netflix-eureka-server
в зависимости - включение сервера Eureka в
@SpringBootApplication
, аннотируя его с помощью@EnableEurekaServer
- настройка некоторых свойств
Давайте сделаем это шаг за шагом.
Сначала мы создадим новый проект Maven и поместим в него зависимости. Обратите внимание, что мы импортируем spring-cloud-starter-parent
во все проекты, описанные в этом руководстве:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Мы можем проверить последние выпуски Spring Cloud в документации Spring’s Projects .
Затем мы создадим основной класс приложения:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Наконец, мы настроим свойства в формате YAML
, поэтому файлом конфигурации будет application.yml :
server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry: false
Здесь мы настраиваем порт приложения; значение по умолчанию для серверов Eureka —
8761
. Мы говорим встроенному клиенту Eureka
не регистрироваться у себя, потому что наше приложение должно действовать как сервер.
Теперь мы укажем в нашем браузере на http://localhost:8761 , чтобы просмотреть панель инструментов Eureka
, где мы позже проверим зарегистрированные экземпляры.
На данный момент мы можем видеть основные индикаторы, такие как индикаторы статуса и здоровья:
3. Клиент Эврика
Чтобы приложение @SpringBootApplication
было осведомлено об обнаружении, мы должны включить клиент Spring Discovery
(например, spring-cloud-starter-netflix-eureka-client
) в наш путь к классам.
Затем нам нужно аннотировать @Configuration
с помощью @EnableDiscoveryClient
или @EnableEurekaClient.
Обратите внимание, что эта аннотация является необязательной, если у нас есть зависимость spring-cloud-starter-netflix-eureka-client
от пути к классам.
Последний указывает Spring Boot
явно использовать Spring Netflix Eureka для обнаружения служб. Чтобы наполнить наше клиентское приложение некоторыми образцами жизни, мы также включим пакет spring-boot-starter-web
в pom.xml
и реализуем контроллер REST .
Но сначала мы добавим зависимости. Опять же, мы можем предоставить зависимости spring-cloud-starter-parent
определить версии артефакта для нас:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Здесь мы реализуем основной класс приложения:
@SpringBootApplication
@RestController
public class EurekaClientApplication implements GreetingController {
@Autowired
@Lazy
private EurekaClient eurekaClient;
@Value("${spring.application.name}")
private String appName;
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
@Override
public String greeting() {
return String.format(
"Hello from '%s'!", eurekaClient.getApplication(appName).getName());
}
}
И интерфейс GreetingController :
public interface GreetingController {
@RequestMapping("/greeting")
String greeting();
}
Вместо интерфейса мы могли бы также просто объявить сопоставление внутри класса EurekaClientApplication
. Однако интерфейс может быть полезен, если мы хотим разделить его между сервером и клиентом.
Затем мы должны настроить application.yml
с настроенным именем приложения Spring
, чтобы однозначно идентифицировать наш клиент в списке зарегистрированных приложений.
Мы можем позволить Spring Boot
выбрать для нас случайный порт, потому что позже мы будем обращаться к этой службе с ее именем.
Наконец, мы должны сообщить нашему клиенту, где он должен найти реестр:
spring:
application:
name: spring-cloud-eureka-client
server:
port: 0
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
instance:
preferIpAddress: true
Мы решили настроить наш Eureka Client таким образом, потому что этот вид сервиса должен быть легко масштабируем в дальнейшем.
Теперь мы запустим клиент и снова укажем в браузере http://localhost:8761
, чтобы увидеть его статус регистрации на панели Eureka Dashboard. Используя Dashboard, мы можем выполнить дальнейшую настройку, например связать домашнюю страницу зарегистрированного клиента с Dashboard для административных целей. Однако параметры конфигурации выходят за рамки этой статьи:
4. Притвориться клиентом
Чтобы завершить наш проект с тремя зависимыми микросервисами, теперь мы реализуем веб-приложение , потребляющее REST , с помощью
Spring Netflix Feign Client
.
Думайте о Feign
как о шаблоне Spring
RestTemplate
с возможностью обнаружения, использующем интерфейсы для связи с конечными точками. Эти интерфейсы будут автоматически реализованы во время выполнения, и вместо service-urls
будут использоваться service-names
.
Без Feign
нам пришлось бы автоматически подключать экземпляр EurekaClient
к нашему контроллеру, с помощью которого мы могли бы получать служебную информацию по имени службы
в качестве объекта приложения .
Мы будем использовать это приложение
, чтобы получить список всех экземпляров этой службы, выбрать подходящий, а затем использовать эту InstanceInfo
, чтобы получить имя хоста и порт. При этом мы могли бы сделать стандартный запрос с любым http-клиентом:
@Autowired
private EurekaClient eurekaClient;
@RequestMapping("/get-greeting-no-feign")
public String greeting(Model model) {
InstanceInfo service = eurekaClient
.getApplication(spring-cloud-eureka-client)
.getInstances()
.get(0);
String hostName = service.getHostName();
int port = service.getPort();
// ...
}
RestTemplate также можно использовать для доступа к клиентским службам
Eureka
по имени, но эта тема выходит за рамки этой статьи.
Чтобы настроить наш проект Feign Client
, мы добавим в его pom.xml
следующие четыре зависимости :
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Клиент Feign
находится в пакете spring-cloud-starter-feign
. Чтобы включить его, мы должны аннотировать @Configuration
с помощью @EnableFeignClients
. Чтобы использовать его, мы просто аннотируем интерфейс с помощью @FeignClient(“service-name”)
и автоматически подключаем его к контроллеру.
Хорошим методом создания таких клиентов
Feign
является создание интерфейсов с аннотированными методами @RequestMapping
и помещение их в отдельный модуль. Таким образом, они могут быть разделены между сервером и клиентом. На стороне сервера мы можем реализовать их как @Controller
, а на стороне клиента их можно расширить и аннотировать как @FeignClient
. [
](/lessons/b/-spring-requestmapping)
Кроме того, в проект необходимо включить пакет spring-cloud-starter-eureka
и активировать его, аннотировав основной класс приложения с помощью @EnableEurekaClient
.
Зависимости spring-boot-starter-web
и spring-boot-starter-thymeleaf
используются для представления представления, содержащего данные, извлеченные из нашей службы REST
.
Это будет наш интерфейс Feign Client
:
@FeignClient("spring-cloud-eureka-client")
public interface GreetingClient {
@RequestMapping("/greeting")
String greeting();
}
Здесь мы реализуем основной класс приложения, который одновременно выступает в роли контроллера:
@SpringBootApplication
@EnableFeignClients
@Controller
public class FeignClientApplication {
@Autowired
private GreetingClient greetingClient;
public static void main(String[] args) {
SpringApplication.run(FeignClientApplication.class, args);
}
@RequestMapping("/get-greeting")
public String greeting(Model model) {
model.addAttribute("greeting", greetingClient.greeting());
return "greeting-view";
}
}
Это будет шаблон HTML для нашего представления:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Greeting Page</title>
</head>
<body>
<h2 th:text="${greeting}"/>
</body>
</html>
Конфигурационный файл application.yml
почти такой же, как и в предыдущем шаге:
spring:
application:
name: spring-cloud-eureka-feign-client
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
Теперь мы можем построить и запустить этот сервис. Наконец, мы укажем нашему браузеру http://localhost:8080/get-greeting
, и он должен отобразить что-то вроде следующего:
Hello from SPRING-CLOUD-EUREKA-CLIENT!
5. « TransportException:
невозможно выполнить запрос на любом известном сервере»
При запуске серверов Eureka мы часто сталкиваемся с такими исключениями, как:
com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
В основном это происходит из-за неправильной настройки в application.properties
или application.yml
. Eureka
предоставляет два свойства для клиента, которые можно настроить:
registerWithEureka:
Если мы установим для этого свойства значениеtrue,
то при запуске сервера встроенный клиент попытается зарегистрироваться на сервере Eureka.fetchRegistry:
если мы настроим это свойство как true, встроенный клиент попытается получить реестрEureka .
Теперь , когда мы запускаем сервер Eureka, мы не хотим регистрировать встроенный клиент для настройки себя на сервере .
Если мы отметим вышеуказанные свойства как истинные
(или просто не настроим их, так как они истинны
по умолчанию), то при запуске сервера встроенный клиент попытается зарегистрироваться на сервере Eureka
, а также попытается получить реестр , который пока недоступен. В результате получаем TransportException
.
Поэтому мы никогда не должны настраивать эти свойства как истинные
в серверных приложениях Eureka .
Правильные настройки, которые следует поместить в application.yml
:
eureka:
client:
registerWithEureka: false
fetchRegistry: false
6. Заключение
В этой статье мы узнали, как реализовать реестр служб с помощью Spring Netflix Eureka Server
и зарегистрировать в нем несколько клиентов Eureka
.
Поскольку наш клиент Eureka
из шага 3 прослушивает случайно выбранный порт, он не знает его местоположения без информации из реестра. С Feign Client
и нашим реестром мы можем найти и использовать службу REST
, даже если местоположение меняется.
Наконец, мы увидели общую картину использования службы обнаружения в микросервисной архитектуре.
Как обычно, мы можем найти исходники на GitHub ,
где также есть набор связанных с Docker
файлов, которые можно использовать с docker-compose
для создания контейнеров из нашего проекта.