简体   繁体   中英

How to configure zone Spring Cloud Zookeeper

I've a 3 front-end application and 3 back end application, Let us say 1 Virtual Machine hosts both front-end and back end application as shown in below diagram, Each front-end application connects to back end using discovery client powered by zookeeper.

在此处输入图片说明

Now I want to create network affinity or zone such that FE1 connects to BE1 if available, if BE1 is down connect to BE2/BE3. Can this be achieved in spring-cloud-zookeeper?

Though this can be done using eureka, but I would prefer to do it using zookeeper.


EDIT

Ok in eureka we can set the zone field and ribbon can do zone affinity in client based on zone field retrieved from eureka for each server. The issue is in zookeeper though ribbon uses the same zonepreference filter but it since zookeeper does not pass the zone info, it always remains UNKNOWN , hence zone filtering is not applied.

As workaround what I tried is pass zone info as metadata while registering service as shown below.

spring:
  application:
    name: kp-zk-server
  cloud:
    zookeeper:
      discovery:
        metadata:
          zone: default

Now in client create ribbon configuration as retrieve the zone info from metadata as filter as shown below.

@Configuration
public class DefaultRibbonConfig {

    @Value("${archaius.deployment.zone:default}")
    private String zone;

    private Predicate<Server> filter = server -> {
        if (server instanceof ZookeeperServer) {
            ZookeeperServer zkServer = (ZookeeperServer) server;
            String str = zkServer.getInstance().getPayload().getMetadata().get("zone");
            return zone.equals(str);
        }
        return true;
    };

    @Bean
    public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
        return new ServerListFilter<Server>() {

            @Override
            public List<Server> getFilteredListOfServers(List<Server> servers) {
                List<Server> selected = servers.stream().filter(filter).collect(Collectors.toList());
                return selected.isEmpty() ? servers : selected;
            }
        };
    }

} 

boostrap.yml

archaius:
  deployment:
    zone: Zone1
spring:
  application:
    name: kp-zk-consumer
  cloud:
    zookeeper:
      dependency:
        enabled: true
        resttemplate:
          enabled: false
      discovery:
        enabled: true
      default-health-endpoint: /actuator/health
      dependencies:
        kWebClient:
          path: /kp-zk-server
          loadBalancerType: ROUND_ROBIN
          required: true
#ribbon:
#  NIWSServerListFilterClassName: io.github.kprasad99.zk.KZoneAffinityServerFilter

Problem

Now the problem is my custom filter class is not being enabled/used, ribbon is still using the default zone filter, if I define the configuration using @RibbonClients

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)

However, if I declare using ribbon.NIWSServerListFilterClassName the filter is not applied, but in this case I cannot set the zone property, need to hardcode the zone property.

As far as I know this isn't possible with Zookeeper out of the box. However, you could achieve the same result by using spring-cloud-loadbalancer and a custom ServiceInstanceSupplier which extends DiscoveryClientServiceInstanceSupplier and filters the instances based on given metadata that has been set, or return the complete list of discovered instances if none matched the criteria to provide you some fallback. This is a generic solution that could solve your question even if you're running in the same datacenter for example.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM