Статьи

HA и зона близости с Spring Cloud Netflix Eureka

Из этого туториала Вы узнаете, как настроить сходство зон в Spring Cloud Netflix Eureka .

Что вы будете строить

Вы создадите три приложения:

  1. API Gateway — Spring Cloud Netflix Zuul

  2. Сервисный реестр — Spring Cloud Netflix Eureka

  3. REST Service — Spring Cloud

Все это необходимо для того, чтобы убедиться в правильности настройки привязки зоны. Каждый из них будет развернут дважды, по одному на зону.

Предварительно Req

  • JDK 1.8

  • Текстовый редактор или ваш любимый IDE

  • Maven 3.0+

Зона близости

Неважно, какой архитектурный стиль использует приложение, это распространенный случай, когда одно и то же приложение развертывается в разных регионах / центрах обработки данных и используется некоторая техника для хранения запросов в одной и той же зоне.

В архитектуре микросервисов также необходимо достичь того же, но эту технику необходимо применять с использованием шаблона проектирования реестра служб .

Весеннее Облако Netflix

Spring Cloud Netflix позволяет легко реализовать необходимые шаблоны для микросервисов .

Создание приложений

В этом руководстве мы создадим три приложения, и, если вы знакомы с spring-cloud, это будет легкая работа, все созданные приложения — не что иное, как простой исполняемый jar -загрузчик .

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

Базовые зависимости

Добавьте следующие зависимости для всех приложений. Если для какого-либо конкретного приложения есть разница, это будет упомянуто в каждом конкретном потоке.

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Edgware.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

API-шлюз

Первым приложением, которое мы создадим, будет API-шлюз, использующий Spring Cloud Netflix Zuul .

Сначала добавьте следующую зависимость в файл pom.xml .

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

Конфигурация Java

Теперь просто создать главный SpringApplication класс добавление @EnableZuulProxy .

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

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

}

Сервисный реестр

Второе приложение, которое мы создадим, будет Service Registry с использованием Spring Cloud Netflix Eureka .

Сначала добавьте следующую зависимость в файл pom.xml .

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

Конфигурация Java

Теперь просто создать главный SpringApplication  класс добавление @EnableEurekaServer .

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

@EnableEurekaServer
@SpringBootApplication
public class ServiceDiscoveryApplication {

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

Простой ОТДЫХ Сервис

Третье приложение не содержит ничего, кроме  конечной точки REST, чтобы гарантировать, что каждый вызов из каждого региона останется в запрошенном регионе. Для этого приложения нечего добавить в базу pom.xml .

Конфигурация Java

Чтобы упростить задачу, я создаю основной класс с помощью вложенного RestController , следующий контроллер возвращает зону, в которой развернуто это приложение.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;

@EnableDiscoveryClient
@SpringBootApplication
public class SimpleService {

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

    @RestController
    class SimpleController {

        @Value("${eureka.instance.metadataMap.zone}")
        private String zone;

        @GetMapping(value = "/zone", produces = APPLICATION_JSON_UTF8_VALUE)
        public String zone() {
            return "{\"zone\"=\"" + zone + "\"}";
        }

    }
}

Свойства конфигурации

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

src/main/resources/application.yml
src/main/resources/application-zone1.yml
src/main/resources/application-zone2.yml

Примечание . Суффикс в имени файла будет использоваться в качестве имени профиля.

Сервисный реестр

# src/main/resources/application.yml

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    region: region-1
    service-url:
      zone1: http://localhost:8761/eureka/
      zone2: http://127.0.0.1:8762/eureka/
    availability-zones:
      region-1: zone1,zone2

spring.profiles.active: zone1

Все следующие свойства находятся в  пространстве имен eureka.client .

Свойство Описание
область

Строка ,  содержащее имя для региона , в котором будет развернуто приложение

сервис URL

Карта ,  содержащая список доступных зон для данного региона

наличие-зона

Карта ,  содержащая разделенный запятыми список зон для данного региона

Свойства register-with-eureka  и fetch-registry  запрещают добавление Service Registry в список приложений, но это не так важно для этой настройки.

# src/main/resources/application-zone1.yml

server.port: 8761

eureka:
  instance:
    hostname: localhost
    metadataMap.zone: zone1
# src/main/resources/application-zone2.yml

server.port: 8762

eureka:
  instance:
    hostname: 127.0.0.1
    metadataMap.zone: zone2

Для  профилей -zone1  и -zone2 единственная разница — это server.port , фактическая зона, настроенная в eureka.metadataMap.zone,  и в этом случае имя хоста , каждый сервер Eureka должен работать под своим именем хоста; поскольку я работаю на одной машине, я называю ее 127.0.01  и localhost .

Примечание . Нет необходимости добавлять имя хоста,  если вы работаете на разных машинах.

шлюз

# src/main/resources/application.yml

eureka:
  client:
    prefer-same-zone-eureka: true
    region: region-1
    service-url:
      zone1: http://localhost:8761/eureka/
      zone2: http://127.0.0.1:8762/eureka/
    availability-zones:
      region-1: zone1,zone2

spring:
  profiles.active: zone1
  application.name: gateway

management.security.enabled: false

Основным отличием здесь является свойство eureka.client.prefer-same-zone-eureka , оно сообщает приложению, что всякий раз, когда ему нужно сделать вызов другому EurekaClient,  оно будет вызывать его, используя ту же зону, где развернут вызывающий объект . Если в той же зоне нет доступного клиента, он будет звонить из другой зоны, в которой он доступен.

# src/main/resources/application-zone1.yml

server.port: 8080

eureka:
  instance:
    metadataMap.zone: zone1
# src/main/resources/application-zone2.yml

server.port: 8081

eureka:
  instance:
    metadataMap.zone: zone2

Как и раньше, для каждой конфигурации профиля изменяется только зона доступности и работающий порт.

Простой ОТДЫХ Сервис

Конфигурация для самой службы содержит ту же конфигурацию, что и шлюз .

# src/main/resources/application.yml

eureka:
  client:
    prefer-same-zone-eureka: true
    region: region-1
    service-url:
      zone1: http://localhost:8761/eureka/
      zone2: http://127.0.0.1:8762/eureka/
    availability-zones:
      region-1: zone1,zone2

spring:
  profiles.active: zone1
  application.name: simple-service
# src/main/resources/application-zone1.yml

server.port: 8181

eureka:
  instance:
    metadataMap.zone: zone1
# src/main/resources/application-zone2.yml

server.port: 8182

eureka:
  instance:
    metadataMap.zone: zone2

Построить и запустить

Пришло время создавать приложения; если вы создаете приложение, используя maven (как я сделал), просто создайте их, выполнив:

$ mvn clean package

Сразу после этого просто запустите каждое приложение, добавив определенный профиль в командную строку, например:

$ java -jar target/*.jar --spring.profiles.active=zone1

Примечание : Помните , что вам нужно запустить каждое приложение в два раза, один раз в профиле: zone1  и zone2 .

Проверка

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

$ curl http://localhost:8080/simple-service/zone

{"zone"="zone1"}
$ curl http://localhost:8081/simple-service/zone

{"zone"="zone2"}

Примечание . Разница между каждой зоной здесь — это server.port .

Проверка отказоустойчивости зоны

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

  1. Остановите простой сервис  на zone2 .

  2. Сделайте запрос на простое обслуживание  через шлюз  на zone2 .

$ curl http://localhost:8081/simple-service/zone

Ожидаемый результат будет теперь JSON ,  содержащий  {"zone"="zone1"}.

Когда простой сервис  для zone1  запущен, запущен и зарегистрирован на Eureka Server,  тот же самый curl должен ответить  {"zone"="zone2"} снова.

Примечание:  Это займет некоторое время на простой-службы  доступны в противоположной зоне, будьте терпеливы и получайте удовольствие!

Резюме

Поздравляем! Вы только что создали и настроили API-шлюз, реестр служб и простую службу REST, которая учитывает привязку к зонам, повышая устойчивость ваших микросервисов и высокую доступность.