spring cloud Eureka高级特性--分区

1.准备

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.搭建

2个注册中心

region1-zone1(region1区域内的zone1),region1-zone2(region1区域内的zone2)

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);
    }
}

3.验证
先启动两个注册中心: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提供服务。
在这里插入图片描述

4.解释:

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

打开debug

logging.level.root=debug

过程解释:

1.此时region1-zone1-service-hi-1、region1-zone1-service-hi-2、region1-zone2-service-hi-1都还存在于ribbon的服务列表中。由于服务分区的原因,ribbon只会轮询使用zone1中的服务即region1-zone1-service-hi-1和region1-zone1-service-hi-2服务。

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

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

因为存在心跳机制,默认情况下,服务的超时时间是90s,服务和注册中心的心跳间隔是30s,我们可以看下spring cloud的文档:

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

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

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

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

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

注册中心选择逻辑:
  1. 如果prefer-same-zone-eureka为false,按照service-url下的 list取第一个注册中心来注册,并和其维持心跳检测。不会再向list内的其它的注册中心注册和维持心跳。只有在第一个注册失败的情况下,才会依次向其它的注册中心注册,总共重试3次,如果3个service-url都没有注册成功,则注册失败。每隔一个心跳时间,会再次尝试。
  2. 如果prefer-same-zone-eureka为true,先通过region取availability-zones内的第一个zone,然后通过这个zone取service-url下的list,并向list内的第一个注册中心进行注册和维持心跳,不会再向list内的其它的注册中心注册和维持心跳。只有在第一个注册失败的情况下,才会依次向其它的注册中心注册,总共重试3次,如果3个service-url都没有注册成功,则注册失败。每隔一个心跳时间,会再次尝试。

所以说,为了保证服务注册到同一个zone的注册中心,一定要注意availability-zones的顺序,必须把同一zone写在前面

我稍微修改了一下,您也可以去看原文spring cloud之eureka高可用集群和服务分区

发布了20 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/SuperBins/article/details/101376604