java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > eureka高可用集群和服务分区

spring cloud之eureka高可用集群和服务分区解析

作者:凶狠的士兵76

这篇文章主要介绍了spring cloud之eureka高可用集群和服务分区解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

准备

1.首先,在C:\WINDOWS\System32\drivers\etc\hosts文件里面添加一下映射,如果不添加也没关系,只是如果是单机环境,在eureka首页中的replicas那一项看到的其它注册中心都是localhost,我这里为了方便理解就添加了映射。

2.为了方便理解,我这里是单个application用一个module,没有采用通过多个profile开启多个application的做法,而且这样做一会儿验证起来也比较清晰。

3.必要的一些概念

先看官方的这张图:

springcloud中eureka的默认region是us-east-1,一个region下可以有多个zone。

比如zone1内有服务A,zone2内也有服务A,消费者A(这里指调用服务A的client)如果属于zone1,他就会优先调用zone1,如果zone1内的服务都不可用了,就会调用zone2中的服务A,这种调用方式就是服务分区。

分区其实就是建立在集群之上,zone1和zone2构成了集群,但是消费者A调用zone1的时候可能开销会小一些,所以可以让他优先调用zone1内的服务A。

搭建

2个注册中心

region1-zone1:

application.properties:

#端口
server.port=8761
#主机名
eureka.instance.hostname=region1-zone1
#应用名称
spring.application.name=eureka-server
 
#是否注册自身到eureka服务器
eureka.client.register-with-eureka=true
#是否获取eureka服务器注册表上的注册信息
eureka.client.fetch-registry=true
 
#false表示在此eureka服务器中关闭自我保护模式,所谓自我保护模式,默认true
eureka.server.enableSelfPreservation=false
 
#配置这个eureka server注册中心所属的region,默认值us-east-1
eureka.client.region=region1
 
#region1内的所有zone,提取第一个作为自己的zone
eureka.client.availability-zones.region1=region1-zone1,region1-zone2
 
#region1内的所有其它zone的注册中心
eureka.client.service-url.region1-zone2=http://region1-zone2:8764/eureka/

启动类:

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

region1-zone2:

server.port=8764 
eureka.instance.hostname=region1-zone2
spring.application.name=eureka-server
 
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.server.enableSelfPreservation=false
 
eureka.client.region=region1
eureka.client.availability-zones.region1=region1-zone2,region1-zone1
eureka.client.service-url.region1-zone1=http://region1-zone1:8761/eureka/

启动类:同region1-zone1

3个service-hi服务

我这里用前缀用来区分他们分别属于哪个zone。

region1-zone1-service-hi-1:

server.port=8762 
spring.application.name=test-zone
eureka.client.region=region1
 
eureka.client.availability-zones.region1=region1-zone1,region1-zone2
eureka.client.service-url.region1-zone1=http://region1-zone1:8761/eureka/
eureka.client.service-url.region1-zone2=http://region1-zone2:8764/eureka/
eureka.client.prefer-same-zone-eureka=true
eureka.instance.prefer-ip-address=true
 
#属于哪一个zone
eureka.instance.metadata-map.zone=region1-zone1
 
#自定义信息,验证的时候用
info=region1-zone1-service-hi-1

启动类:

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

controller:

@RestController
public class HelloController { 
    @Value("${info}") 
    private String info; 
    @RequestMapping(value="/hi")
    public String hi() {
        return info;
    }
}

region1-zone1-service-hi-2:

server.port=8763 
spring.application.name=test-zone
eureka.client.region=region1
eureka.client.availability-zones.region1=region1-zone1,region1-zone2
eureka.client.service-url.region1-zone1=http://region1-zone1:8761/eureka/
eureka.client.service-url.region1-zone2=http://region1-zone2:8764/eureka/
eureka.client.prefer-same-zone-eureka=true
eureka.instance.prefer-ip-address=true 
eureka.instance.metadata-map.zone=region1-zone1 
info=region1-zone1-service-hi-2

启动类、controller都和region1-zone1-service-hi-1相同

region1-zone2-service-hi-1:

server.port=8765
 
spring.application.name=test-zone
eureka.client.region=region1
eureka.client.availability-zones.region1=region1-zone2,region1-zone1
eureka.client.service-url.region1-zone1=http://region1-zone1:8761/eureka/
eureka.client.service-url.region1-zone2=http://region1-zone2:8764/eureka/
eureka.client.prefer-same-zone-eureka=true
eureka.instance.prefer-ip-address=true        
eureka.instance.metadata-map.zone=region1-zone2 
info=region1-zone2-service-hi-1

启动类、controller都和region1-zone1-service-hi-1相同

1个consumer

application.properties:

server.port=8888 
spring.application.name=region1-consumer
eureka.client.region=region1
eureka.client.availability-zones.region1=region1-zone1,region1-zone2
eureka.client.service-url.region1-zone1=http://region1-zone1:8761/eureka/
eureka.client.service-url.region1-zone2=http://region1-zone2:8764/eureka/
eureka.client.prefer-same-zone-eureka=true
eureka.instance.prefer-ip-address=true
eureka.instance.metadata-map.zone=region1-zone1
 
logging.level.root=debug
 

controller:

@RestController
public class HiController { 
    @Autowired
    private RestTemplate restTemplate; 
    @RequestMapping(value="/hello")
    public String hi() {
        return restTemplate.getForObject("http://test-zone/hi", String.class);
    }
}

验证

先启动两个注册中心:eureka-server-region1-zone1、eureka-server-region1-zone2。

然后将4个服务启动。

再启动消费者服务。

访问zone1的注册中心:

访问zone2的注册中心:

可以看到每个注册中心都有4个服务,这说明,3个service-hi和一个consumer注册到了集群中所有注册中心上。

打开浏览器访问:http://ip:8888/hello,ip自行改成consumer服务的ip即可,连续访问这个url若干次,可以看到consumer调用的service的始终是zone1中的service-hi-1和service-hi-2,并且由于ribbon的默认负载均衡规则,service-hi-1和service-hi-2被轮询调用。

然后我们关闭zone1中的service-hi-1,再访问若干次,可以发现此时始终只有service-hi-2提供服务了。

然后我们再关闭zone1中的service-hi-2,再访问若干次url,此时zone1中的注册中心已经没有服务提供者可以给consumer消费了,zone2中的service-hi-1开始给consumer提供服务。

解释

1.有的人可能会发现在关闭服务后立即调用会报错,这一点下面做下解释:

打开debug

logging.level.root=debug

这里我截取了一部分心跳日志:

2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8765, 192.168.5.1:8762, 192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : Determining if zone affinity should be enabled with given server list: [192.168.5.1:8762, 192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Filtered List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8762, 192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]: clearing server list (SET op)
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8762]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Setting server list for zones: {region1-zone1=[192.168.5.1:8762, 192.168.5.1:8763]}
[192.168.5.1:8765, 192.168.5.1:8762, 192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : Determining if zone affinity should be enabled with given server list: [192.168.5.1:8762, 192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Filtered List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8762, 192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]: clearing server list (SET op)
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8762]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8763]
2018-06-24 14:06:03.684 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Setting server list for zones: {region1-zone1=[192.168.5.1:8762, 192.168.5.1:8763]}

2.此时region1-zone1-service-hi-1已经下线,但是region1-zone1-service-hi-2和region1-zone2-service-hi-1还存在于ribbon的服务列表中。由于服务分区的原因,ribbon只会使用region1-zone1-service-hi-2服务。

2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8765, 192.168.5.1:8763]
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : Determining if zone affinity should be enabled with given server list: [192.168.5.1:8763]
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : zoneAffinity is overriden. blackOutServerPercentage: 0.0, activeReqeustsPerServer: 0.0, availableServers: 1
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Filtered List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8763]
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]: clearing server list (SET op)
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8763]
2018-06-24 14:07:03.688 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Setting server list for zones: {region1-zone1=[192.168.5.1:8763]}
[192.168.5.1:8765, 192.168.5.1:8763]
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : Determining if zone affinity should be enabled with given server list: [192.168.5.1:8763]
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : zoneAffinity is overriden. blackOutServerPercentage: 0.0, activeReqeustsPerServer: 0.0, availableServers: 1
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Filtered List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8763]
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]: clearing server list (SET op)
2018-06-24 14:07:03.687 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8763]
2018-06-24 14:07:03.688 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Setting server list for zones: {region1-zone1=[192.168.5.1:8763]}

3.此时zone1中的服务:region1-zone1-service-hi-1和region1-zone1-service-hi-2都已经下线,ribbon只能使用region1-zone2-service-hi-1服务

2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8765]
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : Determining if zone affinity should be enabled with given server list: []
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : zoneAffinity is overriden. blackOutServerPercentage: NaN, activeReqeustsPerServer: 0.0, availableServers: 0
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Filtered List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8765]
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]: clearing server list (SET op)
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8765]
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Setting server list for zones: {region1-zone2=[192.168.5.1:8765]}
[192.168.5.1:8765]
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : Determining if zone affinity should be enabled with given server list: []
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.ZoneAffinityServerListFilter       : zoneAffinity is overriden. blackOutServerPercentage: NaN, activeReqeustsPerServer: 0.0, availableServers: 0
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Filtered List of Servers for test-zone obtained from Discovery client: [192.168.5.1:8765]
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]: clearing server list (SET op)
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.netflix.loadbalancer.BaseLoadBalancer  : LoadBalancer [test-zone]:  addServer [192.168.5.1:8765]
2018-06-24 14:08:03.692 DEBUG 2260 --- [erListUpdater-0] c.n.l.DynamicServerListLoadBalancer      : Setting server list for zones: {region1-zone2=[192.168.5.1:8765]}

因为存在心跳机制,默认情况下,服务的超时时间是90s,服务和注册中心的心跳间隔是30s

我们可以看下spring cloud的文档:

eureka.instance.lease-expiration-duration-in-seconds

90

Indicates the time in seconds that the eureka server waits since it received thelast heartbeat before it can remove this instance from its view and there bydisallowing traffic to this instance.

Setting this value too long could mean that the traffic could be routed to theinstance even though the instance is not alive. Setting this value too small couldmean, the instance may be taken out of traffic because of temporary networkglitches.This value to be set to atleast higher than the value specified inleaseRenewalIntervalInSeconds.

大概意思是:

eureka将等待一定的时间(默认90秒)保持实例的存活,过了这个时间如果没有收到最新的心跳,那么eureka将会把这个实例从自己的视图中移除,并且拒绝他的流量。

eureka.instance.lease-renewal-interval-in-seconds

30

Indicates how often (in seconds) the eureka client needs to send heartbeats to eureka server to indicate that it is still alive. If the heartbeats are not received for the period specified in leaseExpirationDurationInSeconds, eurekaserver will remove the instance from its view, there by disallowing traffic to thisinstance.

Note that the instance could still not take traffic if it implementsHealthCheckCallback and then decides to make itself unavailable.

这个是在讲心跳的时间间隔:指示eureka client隔多少时间发送心跳给server,过了这个时间如果没收到心跳,eureka server就会移除超时的eureka client。

所以说,当一个服务下线,eureka server要90s后才能知道这个服务已经不存在了。

为什么我这里调试的时候要禁用保护模式?

当保护模式被触发的时候,实例就永远不会过期,如果zone1中的服务都下线了,由于这个保护模式,eureka并不会让这些实例过期,因此,zone2中的服务就永远调用不到了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文