官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#_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 Eureka服务器认证
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, like http://user:password@localhost: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:password@localhost: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 Eureka的健康检查
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上使用Eureka
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 在亚马逊AWS上使用Eureka
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 修改实例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 使用原生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次心跳-可能是server、provider、consumer)。通过eureka.instance.leaseRenewalIntervalInSeconds配置可以修改心跳周期,它能加快客户端链接到服务端的速度。但在生产环境中最好使用默认值,因为服务器内部有一些对更新周期的预期的计算。
Zones
If you have deployed Eureka clients to multiple zones than you may prefer that those clients leverage services within the same zone before trying services in another zone. To do this you need to configure your Eureka clients correctly.
如果开发人员将Eureka部署到了多个地区,并想在使用时优先使用一个区。那么就需要正确配置Eureka的客户端。
First, you need to make sure you have Eureka servers deployed to each zone and that they are peers of each other. See the section on **zones and regions** for more information.
首先开发人员需要保证不同地区的Eureka服务端都是彼此的节点。更多信息请见 **zones and regions**。
Next you need to tell Eureka which zone your service is in. You can do this using the metadataMap property. For example if service 1 is deployed to both zone 1 and zone 2 you would need to set the following Eureka properties in service 1
其次,开发人员需要通知Eureka你的服务在哪个地区。使用metadataMap属性来实现。例如,服务1注册在地区1和地区2,需要像下文这样配置:
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
dreamingodd原创文章,如转载请注明出处。