1.Eureka Client
服务发现是基于微服务的体系结构的关键原则之一。试图手工配置每个客户端或某种形式的约定可能是困难的,而且可能是脆弱的。Eureka是Netflix服务发现服务器和客户端。可以将服务器配置和部署为高度可用,每个服务器将注册服务的状态复制到其他服务器。
1.1项目导入Eureka-client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
1.2注册Eureka
当客户端向Eureka注册时,它提供了关于自身的元数据——例如主机、端口、健康指示器URL、主页和其他详细信息。Eureka从属于服务的每个实例接收心跳消息。如果心跳在可配置的时间表上失败,实例通常会从注册表中删除。
下面的例子显示了一个最小的Eureka客户端应用程序:
@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引导应用程序。通过在类路径中使用spring-cloud-starter-netflix-eureka-client,应用程序将自动注册到Eureka服务器。定位Eureka服务器需要配置,如下例所示:
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
在前面的示例中,“defaultZone”是一个神奇的字符串回退值,它为任何不表示首选项的客户机提供服务URL(换句话说,它是一个有用的默认值)。
默认的应用程序名称(即服务ID)、虚拟主机和非安全端口(从环境中获取)是${spring.application.name}、${spring.application.name}和${server.port}
。
如果类路径上有spring-cloud-starter-netflix-eureka-client,应用程序就会同时成为Eureka“实例”(也就是说,它注册了自己)和“客户端”(它可以查询注册表来定位其他服务)。实例行为由eureka.instance驱动。*配置键,但是如果您确保您的应用程序具有spring.application.name的值(这是Eureka服务ID或VIP的默认值),那么缺省值是可以的。
有关可配置选项的更多细节,请参见EurekaInstanceConfigBean和EurekaClientConfigBean。
要禁用Eureka发现客户端,设置 eureka.client.enabled = false.
1.3使用Eureka服务器进行身份验证
如果eureka.client.serviceurl.defaultzone url中的一个url内嵌了凭证,则会自动将HTTP基本身份验证添加到您的eureka客户机(卷曲样式,如下所示:http://user:password@localhost:8761/eureka)。对于更复杂的需求,您可以创建一个@Bean类型DiscoveryClientOptionalArgs,并将ClientFilter实例注入其中,所有这些实例都应用于从客户机到服务器的调用。
由于Eureka中的一个限制,不可能支持每个服务器的基本auth凭证,所以只使用找到的第一个集合。
1.4状态页和健康指示器
Eureka实例的状态页和健康指示器分别默认为/info和/health,它们是Spring引导执行器应用程序中有用端点的默认位置。即使对于执行器应用程序,如果使用非默认上下文路径或servlet路径(如server.servletPath=/custom),也需要更改这些设置。下面的例子显示了这两个设置的默认值:
application.yml.
eureka:
instance:
statusPageUrlPath: ${server.servletPath}/info
healthCheckUrlPath: ${server.servletPath}/health
这些链接显示在客户机使用的元数据中,并在某些场景中用于决定是否向应用程序发送请求,因此,如果这些链接是准确的,那么将非常有用。
在Dalston版本中,在更改管理上下文路径时还需要设置状态和健康检查url。这个需求从Edgware版本开始就被删除了。
1.5注册安全的应用程序
如果你的应用想要通过HTTPS联系,你可以在EurekaInstanceConfig中设置两个标志:
eureka.instance.[nonSecurePortEnabled]=[false]
eureka.instance.[securePortEnabled]=[true]
这样做可以使Eureka发布实例信息,显示出对安全通信的明确偏好。Spring Cloud DiscoveryClient总是为这样配置的服务返回一个以https开头的URI。类似地,当以这种方式配置服务时,Eureka(本机)实例信息具有安全的健康检查URL。
由于Eureka内部的工作方式,它仍然为状态和主页发布一个不安全的URL,除非您也显式地覆盖这些URL。您可以使用占位符来配置eureka实例url,如下面的示例所示:
application.yml.
eureka:
instance:
statusPageUrl: https://${eureka.hostname}/info
healthCheckUrl: https://${eureka.hostname}/health
homePageUrl: https://${eureka.hostname}/
(注意,${eureka.hostname}是一个本机占位符,仅在Eureka的后期版本中可用。使用Spring占位符也可以实现同样的效果——例如,使用${eureka.instance.hostName}。
如果您的应用程序在代理后面运行,而SSL终止在代理中(例如,如果您在云计算或其他平台中作为服务运行),那么您需要确保代理“转发”头信息被应用程序拦截和处理。如果在Spring引导应用程序中嵌入的Tomcat容器具有“x - forward -\*”头文件的显式配置,那么这将自动发生。你的应用程序呈现给自己的链接是错误的(错误的主机、端口或协议),这表明你的配置是错误的。
1.6Eureka的健康检查
默认情况下,Eureka使用客户机心跳来确定客户机是否启动。除非另有说明,发现客户端不会根据Spring引导执行器传播应用程序的当前健康检查状态。因此,在成功注册后,Eureka总是宣布应用程序处于“UP”状态。可以通过启用Eureka健康检查来更改此行为,这将导致将应用程序状态传播到Eureka。因此,其他所有应用程序都不会将流量发送到除“UP”之外的州的应用程序。以下示例显示如何为客户端启用健康检查:
application.yml.
eureka:
client:
healthcheck:
enabled: true
eureka.client.healthcheck.enabled=true只能在application.yml中设置。在bootstrap.yml
中设置值,yml会导致不良的副作用,例如在Eureka注册时状态未知。
如果需要对健康检查进行更多控制,可以考虑实现自己的com.netflix.appinfo.HealthCheckHandler。
1.7实例和客户端的Eureka元数据
花点时间了解Eureka元数据是如何工作的是值得的,这样您就可以在您的平台上合理地使用它。有主机名、IP地址、端口号、状态页和健康检查等信息的标准元数据。它们发布在服务注册中心,客户端使用它们直接联系服务。可以向eureka.instance.metadataMap
中的实例注册添加其他元数据。元数据,该元数据可以在远程客户机中访问。通常,附加元数据不会改变客户机的行为,除非客户机知道元数据的含义。本文稍后将介绍一些特殊情况,其中Spring Cloud已经为元数据映射赋予了含义。
1.7.1在云计算平台上使用Eureka
Cloud Foundry有一个全局路由器,所以同一个app的所有实例都有相同的主机名(其他架构类似的PaaS解决方案都有相同的主机名)。这并不一定是使用Eureka的障碍。但是,如果您使用路由器(推荐或强制使用,这取决于平台的设置方式),则需要显式设置主机名和端口号(安全或不安全),以便它们使用路由器。您可能还希望使用实例元数据,以便能够区分客户机上的实例(例如,在自定义负载均衡器中)。默认情况下是eureka.instance.instanceId
is vcap.application.instance_id
,如下例所示:
application.yml.
eureka:
instance:
hostname: ${vcap.application.uris[0]}
nonSecurePort: 80
根据在云计算实例中设置安全规则的方式,您可能能够注册并使用主机VM的IP地址进行直接的服务到服务调用。此功能在Pivotal Web Services (PWS)上还不可用。
1.7.2在AWS上使用Eureka
如果计划将应用程序部署到AWS云,则必须将Eureka实例配置为具有AWS意识。您可以这样做,定制EurekaInstanceConfigBean如下:
@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;
}
1.7.3更改Eureka实例ID
一个普通的Netflix Eureka实例注册的ID等于它的主机名(也就是说,每个主机只有一个服务)。Spring Cloud Eureka提供了一个合理的默认值,其定义如下:
$ { spring.cloud.client.hostname }:$ { spring.application.name }:$ { spring.application.instance_id:$ { server.port } } }
例如myhost:myappname:8080。
通过使用Spring Cloud,您可以通过在eureka.instance.instanceId中提供唯一标识符来覆盖该值。如下例所示:
application.yml.
eureka:
instance:
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
通过前面示例中显示的元数据和部署在localhost上的多个服务实例,将在其中插入随机值以使实例惟一。在Cloud Foundry,vcap.application.instance_id
在Spring引导应用程序中自动填充,因此不需要随机值。
1.8使用EurekaClient
一旦您拥有了一个发现客户机应用程序,就可以使用它从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();
}
不要在@PostConstruct方法或@Scheduled方法中使用EurekaClient(或者在还没有启动ApplicationContext的任何地方)。它是在SmartLifecycle中初始化的(phase=0),所以您最早可以依赖它的可用性是在另一个更高阶段的SmartLifecycle中。
1.8.1 没有Jersey的EurekaClient
默认情况下,EurekaClient使用Jersey进行HTTP通信。如果希望避免来自Jersey的依赖项,可以将其从依赖项中排除。Spring Cloud基于Spring RestTemplate自动配置传输客户端。以下例子显示Jersey被排除在外:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
</exclusion>
</exclusions>
</dependency>
1.9原生Netflix EurekaClient的替代品
你不需要使用原始的Netflix EurekaClient。而且,在某种包装器后面使用它通常更方便。Spring Cloud通过逻辑Eureka服务标识符(vip)而不是物理url支持Feign(REST客户机构建器)和Spring RestTemplate
。要使用物理服务器的固定列表配置Ribbon,可以设置<client>.ribbon.listOfServers
到一个以逗号分隔的物理地址(或主机名)列表,其中是客户机的ID。
您还可以使用org.springframework.cloud.client.discovery。DiscoveryClient,它为discovery client提供了一个简单的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;
}
1.10为何注册服务如此缓慢?
作为一个实例还涉及到注册中心的周期性心跳(通过客户机的serviceUrl),默认持续时间为30秒。直到实例、服务器和客户机的本地缓存中都有相同的元数据(因此可能需要3次心跳),服务才可以被客户机发现。您可以通过设置eureka.instance.leaseRenewalIntervalInSeconds来更改周期。将它设置为小于30的值可以加快将客户机连接到其他服务的过程。在生产环境中,坚持使用默认值可能更好,因为服务器中的内部计算假设了租赁续期。
1.11区域
如果您已经将Eureka客户端部署到多个区域,那么您可能希望这些客户端在尝试在另一个区域中的服务之前使用同一区域中的服务。要设置它,您需要正确配置您的Eureka客户机。
首先,您需要确保将Eureka服务器部署到每个区域,并且它们是彼此的对等点。有关区域和区域的更多信息,请参见zones and regions一节。接下来,您需要告诉Eureka您的服务位于哪个区域。您可以通过使用metadataMap属性来做到这一点。例如,如果服务1同时部署到区域1和区域2,则需要在服务1中设置以下Eureka属性:
区域1的服务1
eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true
区域2的服务1
eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true