1. 程式人生 > >Spring Cloud官方文檔中文版-服務發現:Eureka客戶端

Spring Cloud官方文檔中文版-服務發現:Eureka客戶端

auth locate inter attr context 本地緩存 數據集 god ati

官方文檔地址為:http://cloud.spring.io/spring-cloud-static/Brixton.SR7/#_spring_cloud_netflix

文中例子我做了一些測試在:http://git.oschina.net/dreamingodd/spring-cloud-preparation

Spring Cloud Netflix

This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few simple annotations you can quickly enable and configure the common patterns inside your application and build large distributed systems with battle-tested Netflix components. The patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix), Intelligent Routing (Zuul) and Client Side Load Balancing (Ribbon).

這個項目通過自動配置以及Spring環境和Spring通用編程模型綁定,為Spring Boot提供Netflix OSS集成。開發人員只需要一些簡單的註解,就能利用battletested Netflix 組件,在開發者的軟件中實現和配置通用模式,以及建立大型的分布式系統。 這些通用模式包括服務發現(Eureka),斷路器(Hystrix),智能路由(Zuul),客戶端負載均衡(Ribbon)。

Service Discovery: Eureka Clients

@EnableDiscoveryClient

Service Discovery is one of the key tenets of a microservice based architecture. Trying to hand configure each client or some form of convention can be very difficult to do and can be very brittle. Eureka is the Netflix Service Discovery Server and Client. The server can be configured and deployed to be highly available, with each server replicating state about the registered services to the others.

服務發現 是微服務架構的核心原則之一。使用手動配置或一些約定方式來處理多服務多實例的方式是非常困難,並且十分脆弱的。Eureka同時是Netflix服務發現的服務端和客戶端。服務端可以通過配置和部署實現高可用,實現方式是每個服務端對註冊的服務復制他們的狀態到其他的服務端。

How to Include Eureka Client

To include Eureka Client in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-eureka. See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train.

Registering with Eureka

When a client registers with Eureka, it provides meta-data about itself such as host and port, health indicator URL, home page etc. Eureka receives heartbeat messages from each instance belonging to a service. If the heartbeat fails over a configurable timetable, the instance is normally removed from the registry.

當一個客戶端使用Eureka註冊,它提供主機和端口,健康指標URL,主頁等元數據給Eureka。Eureka會接收到一個服務的每一個實例的心跳信息。如果心跳數據接收失敗(心跳時間可配置時間表),一般來說這個實例就會被刪除。

Example eureka client: @Configuration @ComponentScan @EnableAutoConfiguration @EnableEurekaClient @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);
    }

}

(i.e. utterly normal Spring Boot app). In this example we use @EnableEurekaClient explicitly, but with only Eureka available you could also use @EnableDiscoveryClient. Configuration is required to locate the Eureka server. Example: (這是一個非常普通的Spring Boot App)。在本例中我們顯式使用了@EnableEurekaClient。然後,我們還需要配置去定位Eureka服務端。例如:

application.yml

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

where "defaultZone" is a magic string fallback value that provides the service URL for any client that doesn’t express a preference (i.e. it’s a useful default).

其中defalutZone為不表示首選項的客戶端提供默認的服務URL,是一個魔術字符串,一個後備值。(反正有用就是了)

The default application name (service ID), virtual host and non-secure port, taken from the Environment, are ${spring.application.name}, ${spring.application.name} and ${server.port} respectively.

從環境中取得的默認的服務名(服務ID),虛擬主機和非安全端口分別是${spring.application.name}, ${spring.application.name} and ${server.port}。

@EnableEurekaClient makes the app into both a Eureka "instance" (i.e. it registers itself) and a "client" (i.e. it can query the registry to locate other services). The instance behaviour is driven by eureka.instance.* configuration keys, but the defaults will be fine if you ensure that your application has a spring.application.name (this is the default for the Eureka service ID, or VIP).

@EnableEurekaClient把應用變成一個Eureka“實例”(即自註冊)和一個“客戶端”(即可以查詢註冊器來定位其他的服務)。eureka.instance.*的配置可以用來控制實例的行為,不過如果你有一個spring.application.name(默認的Eureka服務ID),默認的配置就OK。

See EurekaInstanceConfigBean and EurekaClientConfigBean for more details of the configurable options.

了解更多可以看看下面的 EurekaInstanceConfigBean,EurekaClientConfigBean。

Authenticating with the Eureka Server

HTTP basic authentication will be automatically added to your eureka client if one of the eureka.client.serviceUrl.defaultZone URLs has credentials embedded in it (curl style, likehttp://user:[email protected]:8761/eureka). For more complex needs you can create a @Bean of type DiscoveryClientOptionalArgs and inject ClientFilter instances into it, all of which will be applied to the calls from the client to the server.

服務器端加入spring-cloud-starter-security依賴即可使用基於HTTP的認證機制。然後把客戶端請求的defaultZone改成類似http://user:[email protected]:8761/eureka的形式。更深入的細節需要創建一個DiscoveryClientOptionalArgs的Bean並註入ClientFilter實例,當客戶端請求服務器的時候會用到這些東西。

NOTE Because of a limitation in Eureka it isn’t possible to support per-server basic auth credentials, so only the first set that are found will be used.

Status Page and Health Indicator

The status page and health indicators for a Eureka instance default to "/info" and "/health" respectively, which are the default locations of useful endpoints in a Spring Boot Actuator application. You need to change these, even for an Actuator application if you use a non-default context path or servlet path (e.g. server.servletPath=/foo) or management endpoint path (e.g. management.contextPath=/admin). Example:

狀態和健康頁面分別是/info和/health,他們是Spring Actuator支持的URL。因為你一般不會使用默認的context path或servlet path,最好修改一下默認值,如下:

application.yml

eureka:
  instance:
    statusPageUrlPath: ${management.context-path}/info
    healthCheckUrlPath: ${management.context-path}/health

These links show up in the metadata that is consumed by clients, and used in some scenarios to decide whether to send requests to your application, so it’s helpful if they are accurate.

這些鏈接是client之間互相消費的元數據,在一些情境下決定了是否發出請求,所以要盡量將他們設置正確。

Registering a Secure Application

If your app wants to be contacted over HTTPS you can set two flags in the EurekaInstanceConfig, viz eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true] respectively. This will make Eureka publish instance information showing an explicit preference for secure communication. The Spring Cloud DiscoveryClient will always return an https://…; URI for a service configured this way, and the Eureka (native) instance information will have a secure health check URL.

如果你希望系統使用HTTPS協議進行交互,需要以下兩個配置:eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]。它們將使Eureka發布實例信息時明確首選安全通信。服務發現將一直返回https://...;Eureka實例也將獲得一個安全的健康檢查URL。

Because of the way Eureka works internally, it will still publish a non-secure URL for status and home page unless you also override those explicitly. You can use placeholders to configure the eureka instance urls, e.g.

由於Eureka內部不可見,它仍將發布不安全的URL,除非你顯式重寫配置。例如:

applicatio.yml

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

(Note that ${eureka.hostname} is a native placeholder only available in later versions of Eureka. You could achieve the same thing with Spring placeholders as well, e.g. using ${eureka.instance.hostName}.)

(註意一下${eureka.hostname}為Eureka後續版本的占位符,以前版本是${eureka.instance.hostName})。

NOTE If your app is running behind a proxy, and the SSL termination is in the proxy (e.g. if you run in Cloud Foundry or other platforms as a service) then you will need to ensure that the proxy "forwarded" headers are intercepted and handled by the application. An embedded Tomcat container in a Spring Boot app does this automatically if it has explicit configuration for the ‘X-Forwarded-*` headers. A sign that you got this wrong will be that the links rendered by your app to itself will be wrong (the wrong host, port or protocol).

Eureka’s Health Checks

By default, Eureka uses the client heartbeat to determine if a client is up. Unless specified otherwise the Discovery Client will not propagate the current health check status of the application per the Spring Boot Actuator. Which means that after successful registration Eureka will always announce that the application is in ‘UP‘ state. This behaviour can be altered by enabling Eureka health checks, which results in propagating application status to Eureka. As a consequence every other application won’t be sending traffic to application in state other then ‘UP‘.

一般來說,Eureka使用客戶端心跳來確認客戶端的在線狀態。但SpringCloud默認指定了服務發現的客戶端不再通過Actuator傳播應用的當前狀態。這意味著在初次註冊之後,Eureka將一直顯示此應用為“UP”狀態。這裏需要開發人員配置啟用Eureka健康檢查,使服務能廣播自己的應用狀態。然後,其他的應用才能在狀態為“UP”的時候發送請求。具體配置如下:

application.yml

eureka:
  client:
    healthcheck:
      enabled: true

WARNING eureka.client.healthcheck.enabled=true should only be set in application.yml. Setting the value in bootstrap.yml will cause undesirable side effects like registering in eureka with an UNKNOWN status.

WARNING eureka.client.healthcheck.enabled=true這個配置項只能寫在application.yml中。下載bootstratp.yml中為導致不良副作用-註冊Eureka的時候UNKNOWN狀態。

If you require more control over the health checks, you may consider implementing your own com.netflix.appinfo.HealthCheckHandler.

如果需要對健康檢查做更多控制,可以考慮實現自己的com.netflix.appinfo.HealthCheckHandler。

Eureka Metadata for Instances and Clients

It’s worth spending a bit of time understanding how the Eureka metadata works, so you can use it in a way that makes sense in your platform. There is standard metadata for things like hostname, IP address, port numbers, status page and health check. These are published in the service registry and used by clients to contact the services in a straightforward way. Additional metadata can be added to the instance registration in the eureka.instance.metadataMap, and this will be accessible in the remote clients, but in general will not change the behaviour of the client, unless it is made aware of the meaning of the metadata. There are a couple of special cases described below where Spring Cloud already assigns meaning to the metadata map.

為了在平臺中合理使用Eureka,花點時間理解Eureka元數據的工作原理是值得的。標準的元數據包括hostname,IP地址,端口號,狀態頁,健康檢查。客戶端簡單地使用這些發布在註冊機中的元數據去調用服務。可以在服務註冊時加入其他元數據到eureka.instance.metadataMap中,遠程客戶端可以訪問到,除非改變元數據的意義,否則總體上不會改變客戶端行為。後面會描述了幾個特殊情況,Spring Cloud已經指定的元數據集合的意義。(這段理解不能)

Using Eureka on Cloudfoundry

Cloudfoundry has a global router so that all instances of the same app have the same hostname (it’s the same in other PaaS solutions with a similar architecture). This isn’t necessarily a barrier to using Eureka, but if you use the router (recommended, or even mandatory depending on the way your platform was set up), you need to explicitly set the hostname and port numbers (secure or non-secure) so that they use the router. You might also want to use instance metadata so you can distinguish between the instances on the client (e.g. in a custom load balancer). By default, the eureka.instance.instanceId is vcap.application.instance_id. For example:

application.yml

eureka:
  instance:
    hostname: ${vcap.application.uris[0]}
    nonSecurePort: 80

Depending on the way the security rules are set up in your Cloudfoundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls. This feature is not (yet) available on Pivotal Web Services (PWS).

Using Eureka on AWS

If the application is planned to be deployed to an AWS cloud, then the Eureka instance will have to be configured to be AWS aware and this can be done by customizing the EurekaInstanceConfigBean the following way:

@Bean
@Profile("!default")
public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) {
  EurekaInstanceConfigBean b = new EurekaInstanceConfigBean(inetUtils);
  AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
  b.setDataCenterInfo(info);
  return b;
}

Changing the Eureka Instance ID

A vanilla Netflix Eureka instance is registered with an ID that is equal to its host name (i.e. only one service per host). Spring Cloud Eureka provides a sensible default that looks like this: ${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}}. For example myhost:myappname:8080.

Using Spring Cloud you can override this by providing a unique identifier in eureka.instance.instanceId. For example:

application.yml

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

With this metadata, and multiple service instances deployed on localhost, the random value will kick in there to make the instance unique. In Cloudfoundry the vcap.application.instance_id will be populated automatically in a Spring Boot application, so the random value will not be needed.

Using the EurekaClient

Once you have an app that is @EnableDiscoveryClient (or @EnableEurekaClient) you can use it to discover service instances from the Eureka Server. One way to do that is to use the native com.netflix.discovery.EurekaClient (as opposed to the Spring Cloud DiscoveryClient), e.g.

當你有一個@EnableDiscoveryClient(或@EnableEurekaClient)的APP時,你就可以用它從Eureka服務器來發現服務實例了。下面介紹一個使用本地com.netflix.discovery.EurekaClient(對應Spring Cloud DiscoveryClient)的實現方法:

@Autowired
private EurekaClient discoveryClient;

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

TIP Don’t use the EurekaClient in @PostConstruct method or in a @Scheduled method (or anywhere where the ApplicationContext might not be started yet). It is initialized in a SmartLifecycle (with phase=0) so the earliest you can rely on it being available is in another SmartLifecycle with higher phase.

提示 不要在@PostConstruct,@Scheduled方法中(或者任何應用上下文還沒有啟動的時刻)。那時候EurekaClient很可能還沒有被初始化。

Alternatives to the native Netflix EurekaClient

You don’t have to use the raw Netflix EurekaClient and usually it is more convenient to use it behind a wrapper of some sort. Spring Cloud has support for Feign (a REST client builder) and also Spring RestTemplate using the logical Eureka service identifiers (VIPs) instead of physical URLs. To configure Ribbon with a fixed list of physical servers you can simply set <client>.ribbon.listOfServers to a comma-separated list of physical addresses (or hostnames), where <client> is the ID of the client.

通常,開發人員不必使用Netflix原生的EurekaClient,使用包裝好的更為便利。Spring Cloud擁有Feign(一個Rest客戶端Builder)的支持,使用邏輯Eureka服務定位器的Spring RestTemplate代替物理地址URL。用固定的物理服務器列表只需要簡單配置配置Ribbon,設置<client>.ribbon.listOfServers用逗號分隔物理地址列表(或主機名),<client>就是客戶端的ID。

@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?

Being an instance also involves a periodic heartbeat to the registry (via the client’s serviceUrl) with default duration 30 seconds. A service is not available for discovery by clients until the instance, the server and the client all have the same metadata in their local cache (so it could take 3 heartbeats). You can change the period using eureka.instance.leaseRenewalIntervalInSeconds and this will speed up the process of getting clients connected to other services. In production it’s probably better to stick with the default because there are some computations internally in the server that make assumptions about the lease renewal period.

一個Eureka客戶端實例同樣包含一個默認30秒周期性心跳通知註冊機(通過客戶端serviceUrl)。一個服務直到有一個實例被發現時才可用,服務器和客戶端都在本地緩存中有相似的元數據(故有3次心跳)。通過eureka.instance.leaseRenewalIntervalInSeconds配置可以修改心跳周期,它能加快客戶端鏈接到服務端的速度。在生產環境中最好使用默認值,因為服務器內部有一些對更新周期的預期的計算。

dreamingodd原創文章,如轉載請註明出處。

Spring Cloud官方文檔中文版-服務發現:Eureka客戶端