Статьи

Регистрация и обнаружение микросервисов с помощью Spring Cloud и Eureka от Netflix


Первоначально опубликовано Джошом Лонгом в весеннем блоге

Архитектура микросервисного стиля — это не столько создание отдельных сервисов, сколько создание   надежных и отказоустойчивых взаимодействий между сервисами. Хотя фокус на этих взаимодействиях является новым, необходимость в этом фокусе не является. Мы давно знаем, что сервисы не работают в вакууме. Еще до облачной экономики мы знали, что в практическом мире клиенты должны быть защищены от перебоев в обслуживании. Облако позволяет легко воспринимать емкость как эфемерную, текучую. На клиенте лежит бремя управления этой внутренней сложностью.

В этой статье мы рассмотрим, как  Spring Cloud  помогает вам справляться с этой сложностью с помощью реестра служб, такого как Eureka и Consul, и балансировки нагрузки на стороне клиента.

Облачная телефонная книга

Реестр сервисов — это телефонная книга для ваших микросервисов. Каждый сервис регистрируется в реестре сервисов и сообщает реестру, где он находится (хост, порт, имя узла) и, возможно, другие метаданные, относящиеся к сервису, — вещи, которые другие сервисы могут использовать для принятия обоснованных решений по этому поводу. Клиенты могут задавать вопросы о топологии обслуживания («есть ли какие-либо« услуги выполнения », и если да, где?») И возможностях обслуживания («можете ли вы справиться с X, Y и Z?»). Возможно, вы уже используете технологию, которая имеет некоторое представление о кластере (Cassandra, Memcached и т. Д.), И эта информация в идеале хранится в реестре сервисов.

Есть  несколько популярных опций для регистрации сервисов . Netflix построил, а затем открыл свой собственный сервисный реестр  Eureka . Еще один новый, но все более популярный вариант —  Консул . Мы рассмотрим в основном некоторые аспекты интеграции между Spring Cloud и реестром сервисов Eureka Netflix.

Со  страницы проекта Spring Cloud : «Spring Cloud предоставляет разработчикам инструменты для быстрого построения некоторых распространенных шаблонов в распределенных системах (например, управление конфигурацией, обнаружение служб, прерыватели цепи, интеллектуальная маршрутизация, микропрокси-сервер, шина управления, однократный токены, глобальные блокировки, выборы руководителей, распределенные сеансы, состояние кластера). Координация распределенных систем приводит к созданию шаблонов, и разработчики Spring Cloud могут быстро остановить службы и приложения, которые реализуют эти шаблоны. Они будут хорошо работать в любой распределенной среде, включая собственный ноутбук разработчика, голые металлические центры обработки данных и управляемые платформы, такие как Cloud Foundry ».

Spring Cloud уже поддерживает Eureka и Consul, хотя в этом посте я остановлюсь на Eureka, поскольку его можно автоматически загрузить в одной из автоконфигураций Spring Cloud. Эврика реализована на JVM, а Консул — на Go.

Установка Эврика

Поддерживать экземпляр реестра служб Eureka легко, если у вас есть  org.springframework.boot:spring-cloud-starter-eureka-server путь к классам.

package registry;




import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;




@SpringBootApplication
@EnableEurekaServer
public class Application {




public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Мой номинал  src/main/resources/application.yml выглядит так в эти дни.

server:
port: ${PORT:8761}




eureka:
client:
registerWithEureka: false
fetchRegistry: false
server:
waitTimeInMsWhenSyncEmpty: 0

Порт сервиса по умолчанию настроен на хорошо известный 8761 , если  Cloud Foundry «S VCAP_APPLICATION_PORT переменной окружения не доступна. Остальная часть конфигурации просто говорит этому экземпляру не регистрироваться в экземпляре Eureka, который он находит, потому что этот экземпляр … сам по себе. Если вы запускаете его локально, вы можете указать браузер http://localhost:8761 и отслеживать реестр оттуда.

Развертывание Эврика

Spring Cloud  запустит экземпляр Eureka с автоконфигурацией Spring Boot . При развертывании Eureka необходимо учитывать несколько моментов. Во-первых, вы всегда должны   использовать высокодоступную конфигурацию в производстве.  Образец Spring Cloud Eureka  показывает, как развернуть его в конфигурации с высокой доступностью.

Клиенты должны знать, где найти экземпляр Eureka. Если у вас есть DNS, то это может быть одним из вариантов, если вы не загрязняете слишком большое глобальное пространство имен. Если вы  работаете в Platform-as-a-Service и используете приложения в стиле 12-факторных приложений,  то учетные данные службы поддержки являются конфигурацией и находятся вне приложения и часто представляются в виде переменных среды. Однако вы можете получить эффект от службы Eureka прямо сейчас, используя cf CLI  Cloud Foundry  для создания  предоставляемой пользователем службы .

cf cups eureka-service -p '{"uri":"http://host-of-your-eureka-setup"}'

Укажите  host-of-your-eureka-setup на известный хост для вашей высокодоступной установки Eureka. Я подозреваю, что скоро мы увидим способ создания Eureka в качестве вспомогательного сервиса так же, как вы можете создать экземпляр PostgreSQL или ElasticSearch в  Pivotal Cloud Foundry .

Теперь, когда Eureka запущена и работает, давайте использовать ее для соединения некоторых служб друг с другом!

Говори за себя

Сервисы Spring Cloud имеют  spring.application.name свойство. Он используется для вывода конфигурации с сервера конфигурации, для идентификации сервиса для Eureka, и может использоваться во многих других контекстах при создании приложений на основе Spring Cloud. Это значение, как правило src/main/resources/bootstrap.(yml,properties), находится в , которое выбирается раньше при инициализации, чем обычно  src/main/resources/application.(yml,properties). Служба с  org.springframework.cloud:spring-cloud-starter-eureka на classpath будет зарегистрирована в реестре Eureka его  spring.application.name.

src/main/resources/boostrap.yml Файл для каждого из моих услуг выглядит следующим образом , где  my-service это имя службы , что изменения от сервиса:

spring:
application:
name: my-service

Spring Cloud использует информацию  bootstrap.yml при запуске службы, чтобы обнаружить реестр службы Eureka и зарегистрировать службу и ее  spring.application.name, хост, порт и т. Д. Вы можете спросить об этом первом бите. Spring Cloud пытается найти его по известному адресу ( http://127.0.0.1:), но вы можете это изменить. Вот мой src/main/resources/application.yml номинальный микросервис Spring Cloud, хотя  нет никаких причин, по которым он не может существовать на сервере конфигурации Spring Cloud . Может быть много примеров, идентифицирующих себя как  my-service; Eureka добавит информацию о процессе в список регистраций для того же ID.

eureka:
client:
serviceUrl:
defaultZone: ${vcap.services.eureka-service.credentials.uri:http://127.0.0.1:8761}/eureka/




---
spring:
profiles: cloud
eureka:
instance:
hostname: ${APPLICATION_DOMAIN}
nonSecurePort: 80

В этой конфигурации клиент Spring Cloud Eureka знает, как подключиться к экземпляру Eureka, работающему на localhost,  еслиVCAP_SERVICES  переменная среды  Cloud Foundry  не существует или содержит действительные учетные данные.

Бит конфигурации под --- разделителем предназначен для случаев,  когда приложение  запускается под  cloud профилем Spring . Настроить профиль легко, используя  SPRING_PROFILES_ACTIVEпеременную окружения. Вы можете настроить переменные среды Cloud Foundry в своем файлеmanifest.yml  или,  в Cloud Foundry Lattice , в своем  файле Docker .

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

Нажмите обновить веб-интерфейс Eureka через 30 секунд (на момент написания статьи), и вы увидите, что ваши веб-службы зарегистрированы.

Балансировка нагрузки на стороне клиента с помощью ленты

Spring Cloud ссылается на другие сервисы через их  spring.application.name ценность. Знание этого значения может быть полезно во многих случаях при создании сервисов на основе Spring Cloud.

Как вы помните, цель состоит в том, чтобы позволить  клиенту  на основе контекстной информации (которая может меняться от клиента к клиенту) решать, к какому экземпляру службы он будет подключаться. В Netflix есть клиент для балансировки нагрузки на стороне клиента с поддержкой Eureka, который называется  Ribbon,  который широко интегрируется в Spring Cloud. Лента — это клиентская библиотека со встроенными программными балансировщиками нагрузки. Давайте рассмотрим пример, который использует Eureka напрямую, а затем использует его через интеграцию с Ribbon и Spring Cloud.

package passport;




import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.FeignConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.client.RestTemplate;




import java.util.List;




@SpringBootApplication
@EnableEurekaClient
public class Application extends FeignConfiguration {




public static void main(String[] args) {
new SpringApplicationBuilder(Application.class)
.web(false)
.run(args);
}




@Bean
BookmarkClient bookmarkClient() {
return loadBalance(BookmarkClient.class, "http://bookmark-service");
}
}




@Component
class DiscoveryClientExample implements CommandLineRunner {




@Autowired
private DiscoveryClient discoveryClient;




@Override
public void run(String... strings) throws Exception {
List<ServiceInstance> photoServices = discoveryClient.getInstances("photo-service");
photoServices.forEach(System.out::println);




List<ServiceInstance> bookmarkServices = discoveryClient.getInstances("bookmark-service");
bookmarkServices.forEach(System.out::println);
}
}




@Component
class RestTemplateExample implements CommandLineRunner {




@Autowired
private RestTemplate restTemplate;




@Override
public void run(String... strings) throws Exception {
// use the "smart" Eureka-aware RestTemplate
ResponseEntity<List<Bookmark>> exchange = this.restTemplate.exchange(
"http://bookmark-service/{userId}/bookmarks", HttpMethod.GET, null,
new ParameterizedTypeReference<List<Bookmark>>() {}, (Object) "mstine");




exchange.getBody().forEach(System.out::println);
}
}




@Component
class FeignExample implements CommandLineRunner {




@Autowired
private BookmarkClient bookmarkClient;




@Override
public void run(String... strings) throws Exception {
this.bookmarkClient.getBookmarks("jlong").forEach(System.out::println);
}
}




interface BookmarkClient {




@RequestMapping(method = RequestMethod.GET, value = "/{userId}/bookmarks")
List<Bookmark> getBookmarks(@PathVariable("userId") String userId);
}




class Bookmark {
private Long id;
private String href, label, description, userId;




@Override
public String toString() {
return "Bookmark{" +
"id=" + id +
", href='" + href + '\'' +
", label='" + label + '\'' +
", description='" + description + '\'' +
", userId='" + userId + '\'' +
'}';
}




public Bookmark() {
}




public Long getId() {
return id;
}




public String getHref() {
return href;
}




public String getLabel() {
return label;
}




public String getDescription() {
return description;
}




public String getUserId() {
return userId;
}
}

DiscoveryClientExample Боб демонстрирует использование общих Spring Cloud DiscoveryClient опрашивать услуги. Результаты содержат информацию, такую ​​как имя хоста и порт для каждой службы.

RestTemplateExample Боб демонстрирует Ribbon-Aware автоматически конфигурируемый RestTemplate экземпляр. Обратите внимание, что URI использует идентификатор службы, а не фактическое имя хоста. Идентификатор службы из URI извлекается и передается на ленту, которая затем использует балансировщик нагрузки для выбора среди зарегистрированных экземпляров в Eureka, и, наконец, HTTP-вызов выполняется для реального экземпляра службы.

FeignExample Боб демонстрирует использование интеграции Spring Cloud Feign. Feign — это удобный проект от Netflix, который позволяет декларативно описывать клиента REST API с аннотациями на интерфейсе. В этом случае мы хотим сопоставить результаты HTTP от вызовов к  bookmark-service к  BookmarkClient интерфейсу Java. Это сопоставление настроено в  Application классе к началу кодовой страницы:

@Bean
BookmarkClient bookmarkClient() {
return loadBalance(BookmarkClient.class, "http://bookmark-service");
}

URI является ссылкой на службу, а не фактическим именем хоста. Он проходит ту же обработку, что и URI, указанный  RestTemplate в последнем примере.

Довольно круто, а? Вы можете использовать более простой  DiscoveryClient API и совершать вызовы, или использовать RestTemplate клиента с поддержкой ленты и Eureka  или Feign.

Рассмотрение

  • Spring Cloud поддерживает сервисные реестры Eureka и Consul (и, возможно, больше!)
  • DiscoveryClient API может использоваться для интерактивного запроса Eureka дал идентификатор услуги.
  • Лента — это балансировщик нагрузки на стороне клиента
  • RestTemplate Может заменить идентификаторы услуг для имен хостов в URI , и может отложить до ленты , чтобы выбрать услугу.
  • Интеграция Netflix Spring Cloud Feign упрощает создание интеллектуальных клиентов REST с поддержкой Eureka, которые используют ленту для балансировки нагрузки на стороне клиента для выбора доступного экземпляра службы.

Куда пойти отсюда

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

Круговая балансировка нагрузки — это только один из вариантов. Вместо этого вам может потребоваться некоторое представление об узле лидера и выборе лидера. Цели Spring Cloud также поддерживают такую ​​координацию.

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

Код примера доступен в Интернете,  поэтому не стесняйтесь проверить пример на своем локальном компьютере или отправить его в Cloud Foundry с  помощью предоставленного  cf.sh сценария  и различных  manifest.yml файлов.