Spring Cloud Netflix Features(Eureka)翻译

62 阅读1分钟

Service Discovery: Eureka Clients


服务发现是一个微服务架构的一个关键。去手动配置并制定一些约定是非常难以实现的并且不健壮。Eureka是Neflix服务发现Server和Client。Server是可配置的和部署的,每个server都可以将关于注册服务的状态同步给其他server以实现高可用性。

How to Include Eureka Client

为了将Eureka Client添加到你的项目中,添加groupID为org.springframework.cloud,artifactID为spring-cloud-starter-netflix-eureka-client的依赖。参考 Spring Cloud Project page来查询使用当前Spring Cloud Release Train来进行构建项目的细节。

Registering with Eureka

当一个client使用Eureka进行注册时,它会提供类似host,port,health indicator URL,home page等元数据。Eureka接收每个服务实例的心跳,如果在配置的时间内未收到心跳,该实例将会从注册表中移除。

下面是最小版Eureka client应用的示例:

@SpringBootApplication
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }

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

}

该实例是添加了spring-cloud-starter-netflix-eureka-client依赖的Spring Boot应用,添加该依赖会让自动让你的应用注册到Eureka Serer。这里需要配置来告诉Eureka server的问题,如下所示

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

Warning

defaultZone属性是大小写敏感的并且驼峰风格的,因为serviceUrl属性是Map<String,String>。因此,defaultZone属性并不遵循 SpringBoot的 蛇形 命名的规约default-zone.

默认的application name (即 service ID),virtual host以及 non-secure port(取自Environment)分别为${spring.application.name}, ${spring.application.name} and ${server.port}

添加 spring-cloud-starter-netflix-eureka-client依赖让应用成为Eureka的一个实例(将自身注册到Eureka),还成为一个客户端(可以查询其他服务的注册信息)。实例相关的配置是 eureka.instance.*,一般情况下,只要确认你配置了 spring.application.name (Eureka service ID或VIP的默认值),其他的保持默认值就可以。

参考 EurekaInstanceConfigBeanEurekaClientConfigBean 可以查看更多的配置项的细节。

要想禁用掉Eureka Discovery Client,你可以配置eureka.client.enabled=false或者spring.cloud.discovery.enabled=false

Noe

不支持将Spring Cloud Netflix Eureka server的版本作为path参数,这意味着你不能在context path(eurekaServerURLContext)中设置版本。不过,你可以在server URL中去包含版本,例如,defaultZone: localhost:8761/eureka/v2

Authenticating with the Eureka Server

pass

Status Page and Health Indicator

默认的Eureka实例的status page和health indicators分别是/info/health,它们是Spring Boot Actuator应用默认的端点。如果你使用的不是默认的context path或者servlet path(例如,server.servletPath=/custom),你需要配置这些路径,如下所示

eureka:
  instance:
    statusPageUrlPath: ${server.servletPath}/info
    healthCheckUrlPath: ${server.servletPath}/health

这些链接显示在客户端使用的元数据中,并且在某些情况下用于决定是否向您的应用程序发送请求,因此如果它们准确无误将会很有帮助。

Registering a Secure Application

pass

Eureka‘s Health Checks

默认情况下,Eureka使用client的心跳来检查client是否存活,除非另外指定,Discovery Client不会上报应用的健康检查状态。因此,在成功注册之后,Eureka会一直认为应用在UP状态。可通过启用Eureka 健康检查来修改该行为,这会将应用的状态上报至Eureka。如下所示对client启用健康检查。

eureka:
  client:
    healthcheck:
      enabled: true

Warning

不要在 bootstrap.yml中设置eureka.client.healthcheck.enabled=true,否则会导致一些负面结果,比如注册Eureka为UNKOWN状态。

如果想对健康检查有更多控制,可实现com.netflix.appinfo.HealthCheckHandler进行自定义。

Eureka Metadata for Instances and Clients

花点时间理解Eureka元数据是怎么工作是很有必要的,只有理解了才能正确的使用它。像hostname,IP address,port number,status page以及health check这些是标准的元数据,被发布在服务注册中心用来供其他client调用。可以在eureka.instance.metadataMap中添加额外的元数据,并且这些元数据对于其他client是可以获取得到的。通常,这些额外的元数据不会改变client的行为。但是有一些特殊的类,稍后会介绍,SpringCloud已经赋予了其一些其他含义。

Changing the Eureka Instance ID

Eureka实例携带与host name等价的ID进行注册,Spring Cloud Eureka提供了一种默认的ID命名方式:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}},例如,myhost:myappname:8080

你也可以自定义ID命名方式,通过配置 eureka.instance.instanceId来提供唯一的标识符。如下所示

eureka:
  instance:
    instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}

如上例所示,当多个服务实例部署在同一台机器上时,随机数让它们保持其唯一性。 在Cloud Foundry,vcap.application.instance_id会被SpringBoot自动填充,因此不再需要这个随机数。

Using the EurekaClient

只要你的应用是一个discovery client,你就可以使用它来从Eureka Server中获取服务实例。你可以使用原生的 com.netflix.discovery.EurekaClient 来获取服务实例,而不是Spring Cloud 的 DiscoveryClient

@Autowired
private EurekaClient discoveryClient;

public String serviceUrl() {
    InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES", false);
    return instance.getHomePageUrl();
}

Tip

不要在@PostConstruct方法或在@Scheduled方法等ApplicationContext可能还没有完全启动的地方使用EurekaClientEurekaClientSmartLifecyclephase=0的时候初始化,所以您可以依赖它可用的最早时间是在另一个具有更高阶段的SmartLifecycle中。

EurekaClient with Jersey

默认地,EurekaClient使用Spring的RestTemplate进行HTTP请求,如果你期望使用Jersey,你需要添加Jersey依赖到你的classpath下,下面是你需要添加的依赖:

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
</dependency>
<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-apache-client4</artifactId>
</dependency>

Alternatives to the Native Netflix EurekaClient

你还可以使用org.springframework.cloud.client.discovery.DiscoveryClient获取服务实例,它提供了一些简单的API(并不现定于Netflix)。如下所示

@Autowired
private DiscoveryClient discoveryClient;

public String serviceUrl() {
    List<ServiceInstance> list = discoveryClient.getInstances("STORES");
    if (list != null && list.size() > 0 ) {
        return list.get(0).getUri();
    }
    return null;
}

Why Is It so Slow to Register a Service

服务实例会以默认30秒的周期向注册中心发送心跳包。直到实例、server以及client都在他们本地缓存中有了相同的元数据,服务实例才是可被client可用的,这会花费3次心跳。你可以用过设置eureka.instance.leaseRenewalIntervalInSeconds来修改心跳周期。把它设置为小于30秒的时间来加速client访问服务的时间,但在生产环境中,最好还是使用默认值。

Zones

如果你的Eureka client是部署到多个zone的,你应该会想优先使用同一zone的服务。你可以通过配置Eureka client来实现这一需求。

首先,你需要确保每一个zone都部署了Eureka server,并且他们是对等的,更多信息请查阅 zones and regions

然后,你需要通过配置metadataMap属性告诉Eureka你的service在哪个zone。例如,如果service 1zone 1zone 2都部署了,你需要在service1中设置下面的Eureka properties。

Service 1 in Zone 1

eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true

Service 1 in Zone 2

eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true

Refreshing Eureka Clients

默认地,EurekaClentbean是可刷新的,这意味着Eureka Client properties是可以被改变和刷新的。当刷新发生时,Clients会从Eureka server中取消注册,会发生短暂的给定服务实例都不可用状态。可通过配置eureka.client.refresh.enable=false来禁用掉该行为。

Using Eureka with Spring Cloud LoadBanlancer

我们为Spring Cloud Loadbanlancer提供了支持ZonePreferenceServiceInstanceListSupplier。来自Eureka 实例元数据的zone被用来设置spring-cloud-loadbalancer-zone的值。


Service Discovery:Eureka Server


本章节将介绍怎么设置一个Eureka server。

How to Include Eureka Server

添加group ID为org.springframework.cloud,artifact ID为 spring-cloud-starter-netflix-eureka-server的依赖。查阅 Spring Cloud Project page以获取使用当前Spring Cloud Release Train进行构建的细节。

Note

如果你的项目使用了Thymeleaf,Eureka server的FreeMarker模板可能不会正确加载,这种情况需要手动对template loader进行配置

spring:
  freemarker:
    template-loader-path: classpath:/templates/
    prefer-file-system-access: false

How to Run a Eureka Server

下面示例展示了Eureka server的最小版

@SpringBootApplication
@EnableEurekaServer
public class Application {

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

}

该server会在/eureka/*下带有UI的home page和HTTP API端点。

defaultOpenForTrafficCount and its effect on EurekaServer warmup time

Eureka的waitTimeInMsWhenSyncEmpty设置在Spring Cloud Eureka server中并不生效,需要设置eureka.server.defaultOpenForTrafficCount=0来卡其warmup time。

High Availability, Zones and Regions

Eureka server并没有使用后端存储,所有的服务实例都必须发送心跳来保持他们的注册(所以这可以在内存中完成)。Client同样有Eureka 注册的缓存,这样他们就不用每次请求都去请求注册中心。

默认地,每一个Eureka server也是一个Eureka client,并且需要至少一个service URL来定位peer。如果你没有提供,server也会正常工作,但是会打印不能与peer注册的相关日志。

Standalone Mode

client和server的两个缓存以及心跳机制让单体Eureka server也是很有弹性的,只有这里存在一些监控。在单体模式下,你可能想关掉作为client的行为,这样就不会不断请求peer,如下例所示

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

请注意serviceUrl指向同样的host 作为本地实例。

Peer Awareness

Eureka可以通过运行多个实例并互相注册来实现弹性和高可用,实际上,这是一个默认的行为,所以你需要做的只是添加一个有效的serviceUrl指向peer。如下例所示

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: https://peer2/eureka/

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: https://peer1/eureka/

上面例子中,这个YML文件可以用来在两个主机(peer1peer2)上运行同样的server。你可以修改/etc/hosts来添加对应host,然后使用这个配置在一个主机上来测试peer awareness,但不要在生产环境上这样使用。实际上,如果你Eureka server运行的机器知道其hostname(默认是使用java.net.InetAddress获取的),eureka.instance.hostname是不必要的。

When to Prefer IP Address

在一些情况下,Eureka最好是使用服务实例的IP地址而不是其hostname。设置eureka.instance.preferIpAddress=true,那么当应用注册到Eureka时,eureka server会使用其IP address而不是其hostname。

Tip

如果hostname不能由Java确定,那么将会发送给Eureka Ip地址。只有设置 eureka.instance.hostname 才能明确设置hostname。你可以使用环境变量在运行时设置hostname。例如eureka.instance.hostname=${HOST_NAME}