Comment localiser les services par version avec Netflix eureka et ribbon

nous sommes en train d'explorer Condensateur De Flux de Netflix pour étudier leur implémentation d'architectures micro-services. Pour le moment, nos intérêts sont axés sur l'enregistrement des services et la fonctionnalité de recherche dynamique.

parcourant le code, les samples, et la configuration, mais quelque chose n'est pas clair; service de gestion des versions. Si eureka fournit des services de découverte, et ruban eureka est REST client, comment un client dit qu'il a besoin de service 1.2 de service fooBar? Où le client stocke-t-il/obtient-il ce numéro de version; à partir d'un fichier de configuration local comme , ou est-il dynamique obtenu par archaius<!--4?

13
demandé sur raffian 2014-09-16 06:26:02

2 réponses

je ne vois pas en voie de service de gestion des versions dans le documentation pour l'Eureka API REST.

par conséquent, je pense que la meilleure façon de gérer cela serait d'intégrer des informations de version dans votre IDs de service.

disons que nous avons 4 services: Utilisateur,Statistiques,Login et oAuth.

nous venons de mettre à jour le Utilisateur modification de L'API de service fonctionnalité requise pour certaines nouvelles exigences dans le Login service. Ces modifications sont cependant incompatibles avec L'API qui oAuth et personne n'a le temps de mettre à jour ce service. Statistiques le service n'utilise aucune de ces fonctionnalités et ne se soucie donc pas de la version de l'API utilisée. Cela signifie que nous avons besoin à la fois de la nouvelle version du Utilisateur service (1.2) et l'ancienne version (1.1) de la même temps.

On peut le configurer comme ceci:

  • la configuration pour le Utilisateur 1.1 services dit de s'inscrire comme utilisateur "1.1" et "utilisateur"
  • la configuration pour le Utilisateur 1.2 services dit de s'inscrire comme utilisateur "1.2" et "utilisateur"
  • la configuration pour le oAuth le service dit que L'ID du Utilisateur service est "user-1.1"
  • le configuration pour le Login le service dit que L'ID du Utilisateur service est "user-1.2"
  • la configuration pour le Statistiques le service dit que L'ID du Utilisateur le service est "utilisateur"

de Cette façon, le oAuth le service ne communiquera qu'avec l'ancien Utilisateur service Login service avec le nouveau Utilisateur le service, et le Statistiques service Utilisateur service.

vous devriez pouvoir utiliser Archaius pour propager la configuration sur les serveurs.

Notez que si vous relâchez Utilisateur la version 1.3 qui introduit des Modifications incompatibles avec les parties des 1.2 et 1.1 que le Statistiques le service est utilisé vous devrez soit dire le Utilisateur 1.1 et 1.2 services pour s'enregistrer eux-mêmes comme autre chose aussi (comme "utilisateur-statistiques-safe") et de dire à l' Statistiques service à utiliser l'IDENTIFIANT, ou de dire à l' Statistiques service à utiliser l'utilisateur "1.1" ou "l'utilisateur 1.2".

5
répondu Raniz 2015-06-24 02:41:17

1 registres v1 et v2 Eureka

Service 2 découvre et envoie des demandes à 1's v1 et v2 à l'aide de différents Ruban clients

j'ai obtenu cette démo pour travailler en utilisant Spring Cloud bien que blog pourrait trouver à: http://tech.asimio.net/2017/03/06/Multi-version-Service-Discovery-using-Spring-Cloud-Netflix-Eureka-and-Ribbon.html

L'idée, j'ai suivi RestTemplate pour utiliser un autre Ribbon client pour chaque version car chaque client a son propre ServerListFilter.

le service multi-versions inclut la version dans les métadonnées d'enregistrement.


Service 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
...

Service 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 (Voir Ribbon le nom du client correspond au Ribbon clé trouvée dans 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 est similaire mais en utilisant 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;
    }
}
0
répondu ootero 2017-03-06 15:44:58