Service Discovery with Consul
服务发现是基于微服务架构的关键原则之一。尝试手工配置每个客户端或某种形式的约定是非常困难且容易出现的。Consul通过 HTTP API和 DNS提供服务发现服务。Spring Cloud Consul利用HTTP API进行服务注册和发现。这并不会阻止非Spring Cloud应用程序利用DNS界面。Consul Agent服务器在一个 cluster中运行,该服务器通过一个 gossip protocol来通信并使用 Raft consensus protocol。
How to activate
如需激活Consul服务发现,请使用组为`org.springframework.cloud`且工件ID为`spring-cloud-starter-consul-discovery`的starter。请参阅 Spring Cloud Project page了解有关使用当前Spring Cloud Release Train设置构建系统 的详细信息。
Registering with Consul
当一个客户端在Consul中注册时,它会提供有关其自己的元数据,如主机和端口、ID、名称和标签。默认创建一个 HTTP Check,该 HTTP Check使Consul每10秒针对一次`/actuator/health`端点。如果健康检查失败,服务实例将被标为临界值。
示例 Consul 客户端:
@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 Boot 应用程序)。如果 Consul 客户端位于 localhost:8500
以外,则需要配置以找到该客户端。示例:
spring: cloud: consul: host: localhost port: 8500
如果你使用 Spring Cloud Consul Config,并且设置了 spring.cloud.bootstrap.enabled=true
或 spring.config.use-legacy-processing=true
或使用 spring-cloud-starter-bootstrap
,则需要将上述值放在 bootstrap.yml
中,而不是 application.yml
。
默认服务名、实例 ID 和端口,取自 Environment
,分别为 ${spring.application.name}
,Spring 上下文 ID 和 ${server.port}
。
要禁用 Consul 发现客户端,可以将 spring.cloud.consul.discovery.enabled
设置为 false
。当 spring.cloud.discovery.enabled
设置为 false
时,也会禁用 Consul 发现客户端。
要禁用服务注册,可以将 spring.cloud.consul.discovery.register
设置为 false
。
Registering Management as a Separate Service
当通过设置 management.server.port
属性将管理服务器端口设置为与应用程序端口不同的内容时,管理服务将被注册为独立于应用程序服务的单独服务。例如:
spring: application: name: myApp management: server: port: 4452
上述配置将注册以下 2 个服务:
-
Application Service:
ID: myApp Name: myApp
-
Management Service:
ID: myApp-management Name: myApp-management
管理服务将从应用程序服务处继承其 instanceId
和 serviceName
。例如:
spring: application: name: myApp management: server: port: 4452 spring: cloud: consul: discovery: instance-id: custom-service-id serviceName: myprefix-${spring.application.name}
上述配置将注册以下 2 个服务:
-
Application Service:
ID: custom-service-id Name: myprefix-myApp
-
Management Service:
ID: custom-service-id-management Name: myprefix-myApp-management
可以通过以下属性进行进一步自定义:
/** Port to register the management service under (defaults to management port) */ spring.cloud.consul.discovery.management-port /** Suffix to use when registering management service (defaults to "management") */ spring.cloud.consul.discovery.management-suffix /** Tags to use when registering management service (defaults to "management") */ spring.cloud.consul.discovery.management-tags
HTTP Health Check
Consul 实例的运行状况检查默认为 "/actuator/health",这是 Spring Boot Actuator 应用程序中运行状况终结点的默认位置。即使对于 Actuator 应用程序,如果您使用非默认上下文路径或 servlet 路径(例如 server.servletPath=/foo
)或管理终结点路径(例如 management.server.servlet.context-path=/admin
),您都需要更改此设置。
Consul 用于检查运行状况终结点的间隔也可以进行配置。“10s”和“1m”分别代表 10 秒和 1 分钟。
此示例说明了上述内容(有关更多选项,请参阅附录页面中的 spring.cloud.consul.discovery.health-check-*
属性: link:appendix.html)。
spring: cloud: consul: discovery: healthCheckPath: ${management.server.servlet.context-path}/actuator/health healthCheckInterval: 15s
您可以通过设置 spring.cloud.consul.discovery.register-health-check=false
完全禁用 HTTP 运行状况检查。
Applying Headers
可以将标头应用于运行状况检查请求。例如,如果您尝试注册一个使用 Vault Backend的 Spring Cloud Config服务器:
spring: cloud: consul: discovery: health-check-headers: X-Config-Token: 6442e58b-d1ea-182e-cfa5-cf9cddef0722
根据 HTTP 标准,每个头都可以有多个值,在这种情况下,可以提供一个数组:
spring: cloud: consul: discovery: health-check-headers: X-Config-Token: - "6442e58b-d1ea-182e-cfa5-cf9cddef0722" - "Some other value"
TTL Health Check
可以使用 Consul TTL Check来替换默认配置的 HTTP 检查。主要区别在于:应用程序会向 Consul 代理发送心跳信号,而不是 Consul 代理向应用程序发送请求。
应用程序用于发送 ping 的时间间隔也可以进行配置。“10s”和“1m”分别代表 10 秒和 1 分钟。默认值为 30 秒。
此示例说明了上述内容(有关更多选项,请参阅附录页面中的 spring.cloud.consul.discovery.heartbeat.*
属性: link:appendix.html)。
spring: cloud: consul: discovery: heartbeat: enabled: true ttl: 10s
TTL Application Status
对于 Spring Boot Actuator 应用程序,状态由其可用的运行状况终结点决定。当运行状况终结点不可用时(禁用或不是 Spring Boot Actuator 应用程序),它会假定应用程序处于运行状况良好。
在查询运行状况端点时,默认使用根 health group。可以通过设置以下属性来使用不同的运行状况组:
spring: cloud: consul: discovery: heartbeat: actuator-health-group: <your-custom-group-goes-here>
您可以通过设置以下属性来完全禁用运行状况终结点:
spring: cloud: consul: discovery: heartbeat: use-actuator-health: false
Custom TTL Application Status
如果您想配置您自己的应用程序状态机制,只需实现 ApplicationStatusProvider
接口即可
@Bean public class MyCustomApplicationStatusProvider implements ApplicationStatusProvider { public CheckStatus currentStatus() { return yourMethodToDetermineAppStatusGoesHere(); } }
并提供给应用程序上下文:
@Bean public CustomApplicationStatusProvider customAppStatusProvider() { return new MyCustomApplicationStatusProvider(); }
Actuator Health Indicator(s)
如果服务实例是 Spring Boot Actuator 应用程序,可以为它提供以下 Actuator 健康指标。
DiscoveryClientHealthIndicator
当Consul服务发现处于活动状态时,将配置一个 DiscoverClientHealthIndicator供执行器健康端点使用。请参阅 here以了解配置选项。
ConsulHealthIndicator
将配置一个用于验证 ConsulClient
健康状况的指标。
默认情况下,它会检索 Consul 领导节点状态和所有已注册服务。在拥有许多注册服务的部署中,每次执行健康检查时检索所有服务都可能很耗时。要跳过服务检索并仅检查领导节点状态,请将 spring.cloud.consul.health-indicator.include-services-query=false
设为 false。
要禁用指标,请将 management.health.consul.enabled=false
设为 false。
当应用程序在 bootstrap context mode(默认值)中运行时,这个指示器被加载到引导上下文中,并且不会提供给 Actuator 健康端点。
Metadata
Consul 支持服务上的元数据。Spring Cloud 的 ServiceInstance
有一个 Map<String, String> metadata
字段,该字段从 services meta
字段填充。要填充 meta
字段,请在 spring.cloud.consul.discovery.metadata
或 spring.cloud.consul.discovery.management-metadata
属性上设置值。
spring: cloud: consul: discovery: metadata: myfield: myvalue anotherfield: anothervalue
上述配置会产生一个元字段包含 myfield→myvalue
和 anotherfield→anothervalue
的服务。
Generated Metadata
Consul 自动注册会自动生成几个条目。
Key | Value |
---|---|
'group' |
属性 |
'secure' |
如果属性 |
属性 |
属性 |
旧版本的 Spring Cloud Consul 通过解析 spring.cloud.consul.discovery.tags
属性从 Spring Cloud Commons 填充了 ServiceInstance.getMetadata()
方法。不再支持此操作,请迁移到使用 spring.cloud.consul.discovery.metadata
映射。
Making the Consul Instance ID Unique
默认情况下,一个 Consul 实例会以与其 Spring 应用程序上下文 ID 相等的 ID 进行注册。默认情况下,Spring 应用程序上下文 ID 是 ${spring.application.name}:comma,separated,profiles:${server.port}
。在大多数情况下,这样一来便可以在一台机器上运行一个服务的多个实例。如果需要进一步的唯一性,可以使用 Spring Cloud 通过在 spring.cloud.consul.discovery.instanceId
中提供一个唯一标识符来覆盖此唯一性。例如:
spring: cloud: consul: discovery: instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
有了此元数据,并在本地主机上部署了多个服务实例,那么随机值将发挥作用,让实例变得唯一。在 Cloudfoundry 中,vcap.application.instance_id
会在 Spring Boot 应用程序中自动填充,因此不需要随机值。
Looking up services
Using Load-balancer
Spring Cloud支持 Feign(REST 客户端生成器)和 Spring RestTemplate
,用于使用逻辑服务名称/ID查找服务,而不是物理URL。Feign和支持发现的RestTemplate都利用 Spring Cloud LoadBalancer进行客户端负载平衡。
如果你想使用 RestTemplate 访问服务商店,只需声明:
@LoadBalanced @Bean public RestTemplate loadbalancedRestTemplate() { return new RestTemplate(); }
并像下面这样使用它(请注意我们是如何使用来自 Consul 的商店服务名称/ID 而不是完全限定的域名):
@Autowired RestTemplate restTemplate; public String getFirstProduct() { return this.restTemplate.getForObject("https://STORES/products/1", String.class); }
如果你在多个数据中心中拥有 Consul 集群,并且你想要访问另一个数据中心的服务,那么仅有一个服务名称/ID 还不够。在这种情况下,你可以使用属性 spring.cloud.consul.discovery.datacenters.STORES=dc-west
,其中 STORES
是服务名称/ID,而 dc-west
是商店服务所在的数据中心。
Spring Cloud 现在还提供对 Spring Cloud LoadBalancer 的支持。 |
Using the DiscoveryClient
你还可以使用 org.springframework.cloud.client.discovery.DiscoveryClient
,它提供了一个适用于非特定于 Netflix 的发现客户端的简单 API,例如:
@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; }
Consul Catalog Watch
Consul Catalog Watch利用consul来 watch services的能力。Catalog Watch执行一个阻塞Consul HTTP API调用以确定是否已更改任何服务。如果出现新的服务数据,将发布一个心跳事件。
要更改调用配置监视的频率,请更改 spring.cloud.consul.config.discovery.catalog-services-watch-delay
。默认值为 1000,单位为毫秒。延迟是上一次调用和下一次调用开始之间的时间间隔。
要禁用目录监视,请将 spring.cloud.consul.discovery.catalogServicesWatch.enabled=false
设为 false。
监视使用 Spring TaskScheduler
为调用 Consul 安排时间。默认情况下,它是一个拥有 1 个 poolSize
的 ThreadPoolTaskScheduler
。要更改 TaskScheduler
,请创建一个名为 ConsulDiscoveryClientConfiguration.CATALOG_WATCH_TASK_SCHEDULER_NAME
常量的 TaskScheduler
类型 bean。