Подтвердить что ты не робот

Как найти услуги по версии с помощью eflreix и ленты Netflix

В настоящее время мы изучаем Flux Capacitor от Netflix, чтобы изучить их реализацию архитектур микросервиса. Наши интересы в настоящий момент сосредоточены на регистрации услуг и динамических функциональных возможностях.

Просмотр кода, образцов и конфигурации, но что-то непонятное; управление версиями. Если eureka предоставляет службы обнаружения, а ribbon является клиентом REST на основе eureka, как клиент говорит, что ему нужен сервис 1.2 службы fooBar? Где клиент хранит/получает номер версии; из локального файла конфигурации, такого как this, или он динамически получен через archaius?

4b9b3361

Ответ 1

Я не вижу встроенного способа обработки сервисных версий в документации для API Eureka REST.

Поэтому я считаю, что лучший способ справиться с этим - это включить информацию о версиях в свои идентификаторы сервисов.

Скажем, у нас есть 4 службы: User, Statistics, Login и oAuth.

Мы только что обновили API-интерфейс User, чтобы изменить функциональные возможности, необходимые для некоторых новых требований в службе Login. Однако эти изменения несовместимы с API, который использует oAuth, и никто не имеет времени для обновления этой службы. Служба статистики не использует какую-либо из этих функций, поэтому не имеет значения, какая версия API используется. Это означает, что мы должны одновременно работать как с новой версией службы пользователя (1.2), так и с старой версией (1.1).

Мы можем настроить его следующим образом:

  • Конфигурация сервисов User 1.1 говорит о регистрации в качестве "пользователь-1.1" и "пользователь"
  • Конфигурация сервисов User 1.2 говорит о регистрации в качестве "user-1.2" и "user"
  • Конфигурация службы oAuth говорит, что идентификатор службы пользователя "user-1.1"
  • Конфигурация службы "Логин" говорит, что идентификатор службы пользователя "user-1.2"
  • Конфигурация службы статистики говорит, что идентификатор службы пользователя "пользователь"

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

Вы можете использовать Archaius для распространения конфигурации на серверах.

Обратите внимание, что если вы отпустите User version 1.3, вносящую изменения, несовместимые с частями 1.2 и 1.1, которые используются службой статистики, вам придется либо сообщить сервисам User 1.1 и 1.2, чтобы они регистрировались как что-то еще (например, user-statistics-safe ") и сообщить службе статистики использовать этот идентификатор или сообщить службе статистики использовать либо" пользователь-1.1 ", либо" user-1.2 ".

Ответ 2

Сервис 1 регистрирует v1 и v2 с Eureka

Служба 2 обнаруживает и отправляет запросы Сервис 1 v1 и v2 с использованием разных Лента клиентов

Я получил эту демонстрацию для работы с помощью Spring Cloud, хотя блог можно найти по адресу: http://tech.asimio.net/2017/03/06/Multi-version-Service-Discovery-using-Spring-Cloud-Netflix-Eureka-and-Ribbon.html

Идея, с которой я последовала, заключалась в использовании RestTemplate для использования другого клиента Ribbon для каждой версии, поскольку каждый клиент имеет свой собственный ServerListFilter.

Служба с несколькими версиями включает в себя версию в метаданных регистрации.


Сервис 1

application.yml

...
eureka:
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost:8000/eureka/
  instance:
    hostname: ${hostName}
    statusPageUrlPath: ${management.context-path}/info
    healthCheckUrlPath: ${management.context-path}/health
    preferIpAddress: true
    metadataMap:
      instanceId: ${spring.application.name}:${server.port}

---
spring:
   profiles: v1
eureka:
  instance:
    metadataMap:
      versions: v1

---
spring:
   profiles: v1v2
eureka:
  instance:
    metadataMap:
      versions: v1,v2
...

Сервис 2

application.yml

...
eureka:
  client:
    registerWithEureka: false
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost:8000/eureka/

demo-multiversion-registration-api-1-v1:
   ribbon:
     # Eureka vipAddress of the target service
     DeploymentContextBasedVipAddresses: demo-multiversion-registration-api-1
     NIWSServerListClassName: com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
     # Interval to refresh the server list from the source (ms)
     ServerListRefreshInterval: 30000

demo-multiversion-registration-api-1-v2:
   ribbon:
     # Eureka vipAddress of the target service
     DeploymentContextBasedVipAddresses: demo-multiversion-registration-api-1
     NIWSServerListClassName: com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
     # Interval to refresh the server list from the source (ms)
     ServerListRefreshInterval: 30000
...

Application.java

...
@SpringBootApplication(scanBasePackages = {
    "com.asimio.api.multiversion.demo2.config",
    "com.asimio.api.multiversion.demo2.rest"
})
@EnableDiscoveryClient
public class Application {

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

AppConfig.java (см., как имя клиента Ribbon совпадает с ключом Ribbon, найденным в application.yml

...
@Configuration
@RibbonClients(value = {
    @RibbonClient(name = "demo-multiversion-registration-api-1-v1", configuration = RibbonConfigDemoApi1V1.class),
    @RibbonClient(name = "demo-multiversion-registration-api-1-v2", configuration = RibbonConfigDemoApi1V2.class)
})
public class AppConfig {

    @Bean(name = "loadBalancedRestTemplate")
    @LoadBalanced
    public RestTemplate loadBalancedRestTemplate() {
        return new RestTemplate();
    }
}

RibbonConfigDemoApi1V1.java

...
public class RibbonConfigDemoApi1V1 {

    private DiscoveryClient discoveryClient;

    @Bean
    public ServerListFilter<Server> serverListFilter() {
        return new VersionedNIWSServerListFilter<>(this.discoveryClient, RibbonClientApi.DEMO_REGISTRATION_API_1_V1);
    }

    @Autowired
    public void setDiscoveryClient(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
    }
}

RibbonConfigDemoApi1V2.java похож, но используя RibbonClientApi.DEMO_REGISTRATION_API_1_V2

RibbonClientApi.java

...
public enum RibbonClientApi {

    DEMO_REGISTRATION_API_1_V1("demo-multiversion-registration-api-1", "v1"),

    DEMO_REGISTRATION_API_1_V2("demo-multiversion-registration-api-1", "v2");

    public final String serviceId;
    public final String version;

    private RibbonClientApi(String serviceId, String version) {
        this.serviceId = serviceId;
        this.version = version;
    }
}

VersionedNIWSServerListFilter.java

...
public class VersionedNIWSServerListFilter<T extends Server> extends DefaultNIWSServerListFilter<T> {

    private static final String VERSION_KEY = "versions";

    private final DiscoveryClient discoveryClient;
    private final RibbonClientApi ribbonClientApi;

    public VersionedNIWSServerListFilter(DiscoveryClient discoveryClient, RibbonClientApi ribbonClientApi) {
        this.discoveryClient = discoveryClient;
        this.ribbonClientApi = ribbonClientApi;
    }

    @Override
    public List<T> getFilteredListOfServers(List<T> servers) {
        List<T> result = new ArrayList<>();
        List<ServiceInstance> serviceInstances = this.discoveryClient.getInstances(this.ribbonClientApi.serviceId);
        for (ServiceInstance serviceInstance : serviceInstances) {
            List<String> versions = this.getInstanceVersions(serviceInstance);
            if (versions.isEmpty() || versions.contains(this.ribbonClientApi.version)) {
                result.addAll(this.findServerForVersion(servers, serviceInstance));
            }
        }
        return result;
    }

    private List<String> getInstanceVersions(ServiceInstance serviceInstance) {
        List<String> result = new ArrayList<>();
        String rawVersions = serviceInstance.getMetadata().get(VERSION_KEY);
        if (StringUtils.isNotBlank(rawVersions)) {
            result.addAll(Arrays.asList(rawVersions.split(",")));
        }
        return result;
    }
...

AggregationResource.java

...
@RestController
@RequestMapping(value = "/aggregation", produces = "application/json")
public class AggregationResource {

    private static final String ACTORS_SERVICE_ID_V1 = "demo-multiversion-registration-api-1-v1";
    private static final String ACTORS_SERVICE_ID_V2 = "demo-multiversion-registration-api-1-v2";

    private RestTemplate loadBalancedRestTemplate;

    @RequestMapping(value = "/v1/actors/{id}", method = RequestMethod.GET)
    public com.asimio.api.multiversion.demo2.model.v1.Actor findActorV1(@PathVariable(value = "id") String id) {
        String url = String.format("http://%s/v1/actors/{id}", ACTORS_SERVICE_ID_V1);
        return this.loadBalancedRestTemplate.getForObject(url, com.asimio.api.multiversion.demo2.model.v1.Actor.class, id);
    }

    @RequestMapping(value = "/v2/actors/{id}", method = RequestMethod.GET)
    public com.asimio.api.multiversion.demo2.model.v2.Actor findActorV2(@PathVariable(value = "id") String id) {
        String url = String.format("http://%s/v2/actors/{id}", ACTORS_SERVICE_ID_V2);
        return this.loadBalancedRestTemplate.getForObject(url, com.asimio.api.multiversion.demo2.model.v2.Actor.class, id);
    }

    @Autowired
    public void setLoadBalancedRestTemplate(RestTemplate loadBalancedRestTemplate) {
        this.loadBalancedRestTemplate = loadBalancedRestTemplate;
    }
}