【学习笔记】Eureka服务治理代码实例、相关配置和原理机制详解

代码示例

启动一个服务注册中心

通过@EnableEurekaServer注解启动一个服务注册中心提供给其他应用进行对话。这一步非常简单,只需在一个普通的Spring Boot应用中添加这个注解就能开启此功能,比如下面的例子:

 @EnableEurekaServer 
@SpringBootApplication 
public class Application { 
  public static void main(String[] args) { 
    new SpringApplicationBuilder(Application.class).web(true).run(args); 
  } 

在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为,只需在application.properties中增加如下配置:

server.port=1111 

eureka.instance.hostname=localhost 
eureka.client.register-with-eureka=false 
eureka.client.fetch-registry=false 
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

由于后续内容也都会在本地运行,为了与后续要进行注册的服务区分,这里将服务注册中心的端口通过server.port属性设置为1111。 eureka.client.register-with-eureka:由于该应用为注册中心,所以设置为false,代表不向注册中心注册自己。 eureka.client.fetch-registry:由于注册中心的职责就是维护服务实例,它并不需要去检索服务,所以也设置为false。 在完成了上面的配置后,启动应用并访问http://localhost:1111/。可以看到如下图所示的Eureka信息面板,其中Instances currently registered with Eureka栏是空的,说明该注册中心还没有注册任何服务。
在这里插入图片描述

注册服务提供者

在完成了服务注册中心的搭建之后,接下来我们尝试将一个既有的Spring Boot应用加入Eureka的服务治理体系中去。 可以使用上一章中实现的快速入门工程来进行改造,将其作为一个微服务应用向服务注册中心发布自己。首先,修改pom.xml,增加Spring Cloud Eureka模块的依赖,具体代码如下所示:

<dependencies>        

 <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>          
    <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>             <scope>test</scope>         
    </dependency>          
    <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-eureka</artifactId>         </dependency>     
</dependencies>      
<dependencyManagement>         
    <dependencies>             
        <dependency>                 <groupId>org.springframework.cloud</groupId>                 <artifactId>spring-cloud-dependencies</artifactId>                 <version>Brixton.SR5</version>                 <type>pom</type>                 
            <scope>import</scope>             
        </dependency>         
    </dependencies>     
</dependencyManagement> 


改造/hello请求处理接口,通过注入DiscoveryClient对象,在日志中打印出服务的相关内容。

@RestController 
public class HelloController { 

  private final Logger logger = Logger.getLogger(getClass()); 

  @Autowired 
  private DiscoveryClient client; 

  @RequestMapping(value = "/hello", method = RequestMethod.GET) 
  public String index() { 
    ServiceInstance instance = client.getLocalServiceInstance();
  logger.info("/hello, host:" + instance.getHost() + ", service_id:" + instance.getServiceId()); 
        return "Hello World"; 
    } 
 
}
//然后,在主类中通过加上@EnableDiscoveryClient注解,激活Eureka中的DiscoveryClient实现(自动化配置,创建DiscoveryClient接口针对Eureka客户端的EurekaDiscoveryClient实例),才能实现上述Controller中对服务信息的输出。
@EnableDiscoveryClient 
@SpringBootApplication 
public class HelloApplication { 
 
    public static void main(String[] args) { 
        SpringApplication.run(HelloApplication.class, args); 
    } 
 
} 

最后application.properties配置文件中,通过spring.application.name属性来为服务命名,比如命名为hello-service。再通过eureka.client.serviceUrl.defaultZone属性来指定服务注册中心的地址,这里我们指定为之前构建的服务注册中心地址,完整配置如下所示:

spring.application.name=hello-service 

eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ 

下面我们分别启动服务注册中心以及这里改造后的hello-service服务。在hello-service服务控制台中,Tomcat启动之后,com.netflix.discovery.DiscoveryClient对象打印了该服务的注册信息,表示服务注册成功。

我们也可以通过访问Eureka的信息面板,在Instances currently registered with Eureka一栏中看到服务的注册信息。
在这里插入图片描述

高可用注册中心

在微服务架构这样的分布式环境中,我们需要充分考虑发生故障的情况,所以在生产环境中必须对各个组件进行高可用部署,对于微服务如此,对于服务注册中心也一样。但是到本节为止,我们一直都在使用单节点的服务注册中心,这在生产环境中显然并不合适,我们需要构建高可用的服务注册中心以增强系统的可用性。 Eureka Server的设计一开始就考虑了高可用问题,在Eureka的服务治理设计中,所有节点即是服务提供方,也是服务消费方,服务注册中心也不例外。是否还记得在单节点的配置中,我们设置过下面这两个参数,让服务注册中心不注册自己: eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

**Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,**以实现服务清单的互相同步,达到高可用的效果。

下面我们就来尝试搭建高可用服务注册中心的集群。可以在上面实现的服务注册中心的基础之上进行扩展,构建一个双节点的服务注册中心集群。 创建application-peer1.properties,作为peer1服务中心的配置,并将serviceUrl指向peer2:

 spring.application.name=eureka-server 
server.port=1111 

eureka.instance.hostname=peer1 
eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/ 

创建application-peer2.properties,作为peer2服务中心的配置,并将serviceUrl指向peer1:

spring.application.name=eureka-server 
server.port=1112 

eureka.instance.hostname=peer2 
eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/ 

在/etc/hosts文件中添加对peer1和peer2的转换,让上面配置的host形式的serviceUrl能在本地正确访问到;

Windows系统路径为C:\Windows\System32\drivers\etc\hosts。 127.0.0.1 peer1
127.0.0.1 peer2 通过spring.profiles.active属性来分别启动peer1和peer2:java -jar eureka-server-1.0.0.jar --spring.profiles.active=peer1
java -jar eureka-server-1.0.0.jar --spring.profiles.active=peer2

此时访问peer1的注册中心http://localhost:1111/,如下图所示,我们可以看到,registered-replicas中已经有peer2节点的eureka-server了。同样的,我们访问peer2的注册中心http://localhost:1112/,也能看到registered-replicas中已经有peer1节点,并且这些节点在可用分片(available-replicase)之中。我们也可以尝试关闭peer1,刷新http://localhost:1112/,可以看到peer1的节点变为了不可用分片(unavailable-replicas)。

在设置了多节点的服务注册中心之后,服务提供方还需要做一些简单的配置才能将服务注册到Eureka Server集群中。我们以hello-service为例,修改application.properties配置文件,如下所示:

spring.application.name=hello-service 

eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/ 

上面的配置主要对eureka.client.serviceUrl.defaultZone属性做了改动,将注册中心指向了之前我们搭建的peer1与peer2。

服务的发现与消费

通过上面的内容介绍与实践,我们已经搭建起微服务架构中的核心组件—服务注册中心(包括单节点模式和高可用模式)。同时,还对上一章中实现的Spring Boot入门程序做了改造。通过简单的配置,使该程序注册到Eureka注册中心上,成为该服务治理体系下的一个服务,命名为hello-service。现在我们已经有了服务注册中心和服务提供者,下面就来尝试构建一个服务消费者,它主要完成两个目标,发现服务以及消费服务。其中,服务发现的任务由Eureka的客户端完成,而服务消费的任务由Ribbon完成。Ribbon是一个基于HTTP和TCP的客户端负载均衡器,它可以在通过客户端中配置的ribbonServerList服务端列表去轮询访问以达到均衡负载的作用。当Ribbon与Eureka联合使用时,Ribbon的服务实例清单RibbonServerList会被DiscoveryEnabledNIWSServerList重写,扩展成从Eureka注册中心中获取服务端列表。同时它也会用NIWSDiscoveryPing来取代IPing,它将职责委托给Eureka来确定服务端是否已经启动。在本章中,我们对Ribbon不做详细的介绍,读者只需要理解它在Eureka服务发现的基础上,实现了一套对服务实例的选择策略,从而实现对服务的消费。下一章我们会对Ribbon做详细的介绍和分析。 下面我们通过构建一个简单的示例,看看在Eureka的服务治理体系下如何实现服务的发现与消费。 首先,我们做一些准备工作。启动之前实现的服务注册中心eureka-server以及hello-service服务,为了实验Ribbon的客户端负载均衡功能,我们通过java-jar命令行的方式来启动两个不同端口的hello-service,具体如下:

java -jar hello-service-0.0.1-SNAPSHOT.jar --server.port=8081
java -jar hello-service-0.0.1-SNAPSHOT.jar --server.port=8082

在成功启动两个hello-service服务之后,如下图所示,从Eureka信息面板中可以看到名为HELLO-SERVICE的服务中出现了两个实例单元,分别是通过命令行启动的8081端口和8082端口的服务。
在这里插入图片描述
创建一个Spring Boot的基础工程来实现服务消费者,取名为ribbon-consumer,并在pom.xml中引入如下的依赖内容。较之前的hello-service,我们新增了Ribbon模块的依赖spring-cloud-starter-ribbon。

<parent>     

<groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-parent</artifactId>     <version>
    1.3.7.RELEASE
    </version>     
    <relativePath/> <!-- lookup parent from repository -->   </parent>    
<dependencies>     
    <dependency>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-starter-web</artifactId>     </dependency>      
    <dependency>       <groupId>org.springframework.cloud</groupId>       <artifactId>spring-cloud-starter-eureka</artifactId>     </dependency>      
    <dependency>       <groupId>org.springframework.cloud</groupId>       <artifactId>spring-cloud-starter-ribbon</artifactId>     </dependency>    
</dependencies>    
<dependencyManagement>     
    <dependencies>       
        <dependency>         <groupId>org.springframework.cloud</groupId>         <artifactId>spring-cloud-dependencies</artifactId>         <version>Brixton.SR5</version>         
            <type>pom</type>         
            <scope>import</scope>       
        </dependency>     
    </dependencies>   
</dependencyManagement>

创建应用主类ConsumerApplication,通过@EnableDiscoveryClient注解让该应用注册为Eureka客户端应用,以获得服务发现的能力

同时,在该主类中创建RestTemplate的Spring Bean实例,并通过@LoadBalanced注解开启客户端负载均衡。

@EnableDiscoveryClient 
@SpringBootApplication 
public class ConsumerApplication { 
    @Bean   
    @LoadBalanced   
    RestTemplate restTemplate() {     
        return new RestTemplate();   
    }   
    public static void main(String[] args) 
    {     SpringApplication.run(ConsumerApplication.class, args);   
    }  
} 

创建ConsumerController类并实现/ribbon-consumer接口。在该接口中,通过在上面创建的RestTemplate来实现对HELLO-SERVICE服务提供的/hello接口进行调用。**可以看到这里访问的地址是服务名HELLO-SERVICE,而不是一个具体的地址,**在服务治理框架中,这是一个非常重要的特性,也符合在本章一开始对服务治理的解释。

@RestController 

public class ConsumerController { 

@Autowired     
RestTemplate restTemplate;      
@RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)     

public String helloConsumer() {         

return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();     

} 

 } 

在application.properties中配置Eureka服务注册中心的位置,需要与之前的HELLO-SERVICE一样,不然是发现不了该服务的,同时设置该消费者的端口为9000,不能与之前启动的应用端口冲突。

spring.application.name=ribbon-consumer 

server.port=9000  

eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

启动ribbon-consumer应用后,我们可以在Eureka信息面板中看到,当前除了HELLO-SERVICE之外,还多了我们实现的RIBBON-CONSUMER服务。

通过向http://localhost:9000/ribbon-consumer发起GET请求,成功返回了“Hello World”。

此时,我们可以在ribbon-consumer应用的控制台中看到如下信息,Ribbon输出了当前客户端维护的HELLO-SERVICE的服务列表情况。其中包含了各个实例的位置,Ribbon就是按照此信息进行轮询访问,以实现基于客户端的负载均衡。另外还输出了一些其他非常有用的信息,如对各个实例的请求总数量、第一次连接信息、上一次连接信息、总的请求失败数量等。

再尝试发送几次请求,并观察启动的两个HELLO-SERVICE的控制台,可以看到两个控制台会交替打印下面的日志,

com.didispace.web.HelloController : /hello, host:PC-201602152056,
service_id:hello-service

这是我们之前在HelloController中实现的对服务信息的输出,可以用来判断当前ribbon-consumer对HELLO-SERVICE的调用是否是负载均衡的。

Eureka的一些配置

服务注册类配置

关于服务注册类的配置信息,我们可以通过查看org.springframework.cloud.netflix.eureka.EurekaClientConfigBean的源码来获得比官方文档中更为详尽的内容,这些配置信息都以eureka.client为前缀。下面我们针对一些常用的配置信息做进一步的介绍和说明。
指定注册中心
将一个Spring Boot应用纳入Eureka的服务治理体系,除了引入Eureka的依赖之外,就是在配置文件中指定注册中心,主要通过eureka.client.serviceUrl参数实现.
该参数的定义如下所示:

private Map<String, String> serviceUrl = new HashMap<>(); 
{ 
    this.serviceUrl.put(DEFAULT_ZONE, DEFAULT_URL); 
} 
 
public static final String DEFAULT_URL = "http://localhost:8761" + DEFAULT_PREFIX + "/"; 
public static final String DEFAULT_ZONE = "defaultZone"; 

它的配置值存储在HashMap类型中,并且设置有一组默认值,默认值的key为defaultZone、value为http://localhost:8761/eureka/。
当构建了高可用的服务注册中心集群时,我们可以为参数的value值配置多个注册中心的地址(通过逗号分隔)。比如下面的例子:

eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/

另外,为了服务注册中心的安全考虑,很多时候我们都会为服务注册中心加入安全校验。这个时候,在配置serviceUrl时,需要在value值的URL中加入相应的安全校验信息,比如http://<username>:<password>@localhost:1111/eureka。
其中,<username>为安全校验信息的用户名,<password>为该用户的密码。

服务实例类配置

元数据
在org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean的配置信息中,有一大部分内容都是对服务实例元数据的配置,那么什么是服务实例的元数据呢?它是Eureka客户端在向服务注册中心发送注册请求时,用来描述自身服务信息的对象,其中包含了一些标准化的元数据,比如服务名称、实例名称、实例IP、实例端口等用于服务治理的重要信息;以及一些用于负载均衡策略或是其他特殊用途的自定义元数据信息。 在使用Spring Cloud Eureka的时候,所有的配置信息都通过org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean进行加载,但在真正进行服务注册的时候,还是会包装成com.netflix.appinfo.InstanceInfo对象发送给Eureka服务端。这两个类的定义非常相似,我们可以直接查看com.netflix.appinfo.InstanceInfo类中的详细定义来了解原生Eureka对元数据的定义。其中,Map<String,String>metadata=new ConcurrentHashMap<String,String>()是自定义的元数据信息,而其他成员变量则是标准化的元数据信息。Spring Cloud的EurekaInstanceConfigBean对原生元数据对象做了一些配置优化处理,在后续的介绍中,我们也会提到这些内容。 我们可以通过eureka.instance.<properties>=<value>的格式对标准化元数据直接进行配置,其中<properties>就是EurekaInstanceConfigBean对象中的成员变量名。而对于自定义元数据,可以通过eureka.instance.metadataMap.<key>=<value>的格式来进行配置,比如: eureka.instance.metadataMap.zone=shanghai 接下来,我们将针对一些常用的元数据配置做进一步的介绍和说明。

实例名配置

实例名,即InstanceInfo中的instanceId参数,它是区分同一服务中不同实例的唯一标识。在Netflix Eureka的原生实现中,实例名采用主机名作为默认值,这样的设置使得在同一主机上无法启动多个相同的服务实例。所以,在Spring Cloud Eureka的配置中,针对同一主机中启动多实例的情况,对实例名的默认命名做了更为合理的扩展,它采用了如下默认规则:

${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}

对于实例名的命名规则,我们可以通过eureka.instance.instanceId参数来进行配置。比如,在本地进行客户端负载均衡调试时,需要启动同一服务的多个实例,如果我们直接启动同一个应用必然会产生端口冲突。虽然可以在命令行中指定不同的server.port来启动,但是这样还是略显麻烦。实际上,我们可以直接通过设置server.port=0或者使用随机数server.port=${random.int[10000,19999]}来让Tomcat启动的时候采用随机端口。但是这个时候我们会发现注册到Eureka Server的实例名都是相同的,这会使得只有一个服务实例能够正常提供服务。对于这个问题,我们就可以通过设置实例名规则来轻松解决:

eureka.instance.instanceId=${spring.application.name}:${random.int}}

通过上面的配置,利用应用名加随机数的方式来区分不同的实例,从而实现在同一主机上,不指定端口就能轻松启动多个实例的效果。

端点配置

在InstanceInfo中,我们可以看到一些URL的配置信息,比如homePageUrl、statusPageUrl、healthCheckUrl,它们分别代表了应用主页的URL、状态页的URL、健康检查的URL。其中,状态页和健康检查的URL在Spring Cloud Eureka中默认使用了spring-boot-actuator模块提供的/info端点和/health端点。虽然我们在之前的示例中并没有对这些端点做具体的设置,但是实际上这些URL地址的配置非常重要。为了服务的正常运作,我们必须确保Eureka客户端的/health端点在发送元数据的时候,是一个能够被注册中心访问到的地址,否则服务注册中心不会根据应用的健康检查来更改状态(仅当开启了healthcheck功能时,以该端点信息作为健康检查标准)。而/info端点如果不正确的话,会导致在Eureka面板中单击服务实例时,无法访问到服务实例提供的信息接口。 大多数情况下,我们并不需要修改这几个URL的配置,但是在一些特殊情况下,比如,为应用设置了context-path,这时,所有spring-boot-actuator模块的监控端点都会增加一个前缀。所以,我们就需要做类似如下的配置,为/info和/health端点也加上类似的前缀信息:

 management.context-path=/hello 
 
eureka.instance.statusPageUrlPath=\${management.context-path}/info 
eureka.instance.healthCheckUrlPath=${management.context-path}/health 

另外,有时候为了安全考虑,也有可能会修改/info和/health端点的原始路径。这个时候,我们也需要做一些特殊的配置,比如像下面这样:

endpoints.info.path=/appInfo 
endpoints.health.path=/checkHealth 
 
eureka.instance.statusPageUrlPath=/${endpoints.info.path} 
eureka.instance.healthCheckUrlPath=/${endpoints.health.path} 

在上面所举的两个示例中,我们使用了eureka.instance.statusPageUrlPath和eureka.instance.healthCheckUrlPath参数,这两个配置值有一个共同特点,它们都使用相对路径来进行配置。由于Eureka的服务注册中心默认会以HTTP的方式来访问和暴露这些端点,因此当客户端应用以HTTPS的方式来暴露服务和监控端点时,相对路径的配置方式就无法满足需求了。所以,Spring Cloud Eureka还提供了绝对路径的配置参数,具体示例如下所示:

eureka.instance.statusPageUrl=https://${eureka.instance.hostname}/info 
eureka.instance.healthCheckUrl=https://${eureka.instance.hostname}/health 
eureka.instance.homePageUrl=https://${eureka.instance.hostname}/

Eureka服务治理基础架构原理

Eureka服务治理基础架构的三个核心要素:
服务注册中心:Eureka提供的服务端,提供服务注册与发现的功能,也就是在上一节中我们实现的eureka-server。
服务提供者:提供服务的应用,可以是Spring Boot应用,也可以是其他技术平台且遵循Eureka通信机制的应用。它将自己提供的服务注册到Eureka,以供其他应用发现,也就是在上一节中我们实现的HELLO-SERVICE应用。
服务消费者:消费者应用从服务注册中心获取服务列表,从而使消费者可以知道去何处调用其所需要的服务,在上一节中使用了Ribbon来实现服务消费,另外后续还会介绍使用Feign的消费方式。 很多时候,客户端既是服务提供者也是服务消费者。

服务治理机制
在体验了Spring Cloud Eureka通过简单的注解配置就能实现强大的服务治理功能之后,我们来进一步了解一下Eureka基础架构中各个元素的一些通信行为,以此来理解基于Eureka实现的服务治理体系是如何运作起来的。以下图为例,其中有这样几个重要元素: “服务注册中心-1”和“服务注册中心-2”,它们互相注册组成了高可用集群。 “服务提供者”启动了两个实例,一个注册到“服务注册中心-1” 上,另外一个注册到“服务注册中心-2”上。 还有两个“服务消费者”,它们也都分别只指向了一个注册中心
在这里插入图片描述
根据上面的结构,下面我们来详细了解一下,从服务注册开始到服务调用,及各个元素所涉及的一些重要通信行为。
服务提供者

—服务注册
“服务提供者”在启动的时候会通过发送REST请求的方式将自己注册到Eureka Server上,同时带上了自身服务的一些元数据信息。Eureka Server接收到这个REST请求之后,将元数据信息存储在一个双层结构Map中,其中第一层的key是服务名,第二层的key是具体服务的实例名。(我们可以回想一下之前在实现Ribbon负载均衡的例子中,Eureka信息面板中一个服务有多个实例的情况,这些内容就是以这样的双层Map形式存储的。) 在服务注册时,需要确认一下eureka.client.register-with-eureka=true参数是否正确,该值默认为true。若设置为false将不会启动注册操作。

—服务同步

如架构图中所示,这里的两个服务提供者分别注册到了两个不同的服务注册中心上,也就是说,它们的信息分别被两个服务注册中心所维护。此时,由于服务注册中心之间因互相注册为服务,当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中相连的其他注册中心,从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到。

—服务续约

在注册完服务之后,服务提供者会维护一个心跳用来持续告诉Eureka Server:“我还活着”,以防止Eureka Server的“剔除任务”将该服务实例从服务列表中排除出去,我们称该操作为服务续约(Renew)。 关于服务续约有两个重要属性,我们可以关注并根据需要来进行调整
eureka.instance.lease-renewal-interval-in-seconds=30
eureka.instance.lease-expiration-duration-in-seconds=90 eureka.instance.lease-renewal-interval-in-seconds参数用于定义服务续约任务的调用间隔时间,默认为30秒。eureka.instance.lease-expiration-duration-in-seconds参数用于定义服务失效的时间,默认为90秒。 服务消费者取服务 到这里,在服务注册中心已经注册了一个服务,并且该服务有两个实例。当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新一次。 获取服务是服务消费者的基础,所以必须确保eureka.client.fetch-registry=true参数没有被修改成false,该值默认为true。若希望修改缓存清单的更新时间,可以通过eureka.client.registry-fetch-interval-seconds=30参数进行修改,该参数默认值为30,单位为秒。

服务消费者

----获取服务
到这里,在服务注册中心已经注册了一个服务,并且该服务有两个实例。当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新一次。 获取服务是服务消费者的基础,所以必须确保eureka.client.fetch-registry=true参数没有被修改成false,该值默认为true。若希望修改缓存清单的更新时间,可以通过eureka.client.registry-fetch-interval-seconds=30参数进行修改,该参数默认值为30,单位为秒。

----服务调用

服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

----服务下线

在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭期间,我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中,当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线了”。服务端在接收到请求之后,将该服务状态置为下线(DOWN),并把该下线事件传播出去。

服务注册中心

----失效剔除
有些时候,我们的服务实例并不一定会正常下线,可能由于内存溢出、网络故障等原因使得服务不能正常工作,而服务注册中心并未收到“服务下线”的请求。为了从服务列表中将这些无法提供服务的实例剔除,Eureka Server在启动的时候会创建一个定时任务,默认每隔一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除出去。

---- 自我保护
当我们在本地调试基于Eureka的程序时,基本上都会碰到这样一个问题,在服务注册中心的信息面板中出现类似下面的红色警告信息: EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE. 实际上,该警告就是触发了Eureka Server的自我保护机制。之前我们介绍过,服务注册到Eureka Server之后,会维护一个心跳连接,告诉Eureka Server自己还活着。Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,让这些实例不会过期,尽可能保护这些注册信息。但是,在这段保护期间内实例若出现问题,那么客户端很容易拿到实际已经不存在的服务实例,会出现调用失败的情况,所以客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。 由于本地调试很容易触发注册中心的保护机制,这会使得注册中心维护的服务实例不那么准确。所以,我们在本地进行开发的时候,可以使用eureka.server.enable-self-preservation=false参数来关闭保护机制,以确保注册中心可以将不可用的实例正确剔除。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值