使用 Consul 进行服务发现
如何激活
要激活 Consul 服务发现,请使用 group 为 org.springframework.cloud 且 artifact id 为 spring-cloud-starter-consul-discovery 的启动器。有关使用当前 Spring Cloud 发布版本设置构建系统的详细信息,请参阅 Spring Cloud 项目页面。
向 Consul 注册
当客户端向 Consul 注册时,它会提供自己的元数据,例如主机和端口、ID、名称和标签。默认情况下会创建一个 HTTP 检查,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 中。 |
从 Environment 中获取的默认服务名称、实例 ID 和端口分别是 ${spring.application.name}、Spring 上下文 ID 和 ${server.port}。
要禁用 Consul Discovery Client,您可以将 spring.cloud.consul.discovery.enabled 设置为 false。当 spring.cloud.discovery.enabled 设置为 false 时,Consul Discovery Client 也会被禁用。
要禁用服务注册,您可以将 spring.cloud.consul.discovery.register 设置为 false。
将管理注册为独立服务
当管理服务器端口通过设置 management.server.port 属性与应用程序端口不同时,管理服务将作为独立于应用程序服务注册。例如
spring:
application:
name: myApp
management:
server:
port: 4452
上述配置将注册以下两个服务
-
应用程序服务
ID: myApp Name: myApp
-
管理服务
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}
上述配置将注册以下两个服务
-
应用程序服务
ID: custom-service-id Name: myprefix-myApp
-
管理服务
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 健康检查
Consul 实例的健康检查默认为 "/actuator/health",这是 Spring Boot Actuator 应用程序中健康端点的默认位置。如果您使用非默认上下文路径或 servlet 路径(例如 server.servletPath=/foo)或管理端点路径(例如 management.server.servlet.context-path=/admin),则即使对于 Actuator 应用程序,您也需要更改此设置。
Consul 用于检查健康端点的间隔也可以配置。“10s”和“1m”分别表示 10 秒和 1 分钟。
此示例说明了上述内容(有关更多选项,请参阅 附录页 中的 spring.cloud.consul.discovery.health-check-* 属性)。
spring:
cloud:
consul:
discovery:
healthCheckPath: ${management.server.servlet.context-path}/actuator/health
healthCheckInterval: 15s
您可以通过将 spring.cloud.consul.discovery.register-health-check 设置为 false 来完全禁用 HTTP 健康检查。
应用头信息
头信息可以应用于健康检查请求。例如,如果您尝试注册一个使用 Vault 后端 的 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 健康检查
可以使用 Consul TTL 检查 代替默认配置的 HTTP 检查。主要区别在于应用程序向 Consul 代理发送心跳信号,而不是 Consul 代理向应用程序发送请求。
应用程序发送 ping 的间隔也可以配置。"10s" 和 "1m" 分别表示 10 秒和 1 分钟。默认值为 30 秒。
此示例说明了上述内容(有关更多选项,请参阅 附录页 中的 spring.cloud.consul.discovery.heartbeat.* 属性)。
spring:
cloud:
consul:
discovery:
heartbeat:
enabled: true
ttl: 10s
TTL 应用程序状态
对于 Spring Boot Actuator 应用程序,其状态由其可用的健康端点确定。当健康端点不可用时(无论是禁用还是不是 Spring Boot Actuator 应用程序),它假定应用程序处于良好健康状态。
查询健康端点时,默认使用根 健康组。可以通过设置以下属性来使用不同的健康组
spring:
cloud:
consul:
discovery:
heartbeat:
actuator-health-group: <your-custom-group-goes-here>
您可以通过设置以下属性完全禁用健康端点
spring:
cloud:
consul:
discovery:
heartbeat:
use-actuator-health: false
自定义 TTL 应用程序状态
如果您想配置自己的应用程序状态机制,只需实现 ApplicationStatusProvider 接口
@Bean
public class MyCustomApplicationStatusProvider implements ApplicationStatusProvider {
public CheckStatus currentStatus() {
return yourMethodToDetermineAppStatusGoesHere();
}
}
并将其提供给应用程序上下文
@Bean
public CustomApplicationStatusProvider customAppStatusProvider() {
return new MyCustomApplicationStatusProvider();
}
Actuator 健康指标
如果服务实例是 Spring Boot Actuator 应用程序,则可以提供以下 Actuator 健康指标。
DiscoveryClientHealthIndicator
当 Consul 服务发现处于活动状态时,会配置一个 DiscoverClientHealthIndicator 并使其可用于 Actuator 健康端点。有关配置选项,请参见 此处。
ConsulHealthIndicator
配置了一个指标来验证 ConsulClient 的健康状况。
默认情况下,它会检索 Consul leader 节点状态和所有已注册的服务。在有许多已注册服务的部署中,每次健康检查都检索所有服务可能会很昂贵。要跳过服务检索并仅检查 leader 节点状态,请设置 spring.cloud.consul.health-indicator.include-services-query=false。
要禁用该指标,请设置 management.health.consul.enabled=false。
| 当应用程序在 引导上下文模式(默认)下运行时,此指标被加载到引导上下文,并且不可用于 Actuator 健康端点。 |
元数据
Consul 支持服务的元数据。Spring Cloud 的 ServiceInstance 有一个 Map<String, String> metadata 字段,它从服务的 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。
生成的元数据
Consul 自动注册将自动生成一些条目。
| 键 | 值 |
|---|---|
'group' |
属性 |
'secure' |
如果属性 |
属性 |
属性 |
旧版 Spring Cloud Consul 通过解析 spring.cloud.consul.discovery.tags 属性填充 Spring Cloud Commons 中的 ServiceInstance.getMetadata() 方法。此功能不再受支持,请迁移到使用 spring.cloud.consul.discovery.metadata 映射。 |
使 Consul 实例 ID 唯一
默认情况下,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}}}
有了这些元数据,并且在 localhost 上部署了多个服务实例,随机值将起作用以使实例唯一。在 Cloudfoundry 中,vcap.application.instance_id 将在 Spring Boot 应用程序中自动填充,因此不需要随机值。
查找服务
使用负载均衡器
Spring Cloud 支持 Feign(一个 REST 客户端构建器)以及 Spring RestTemplate,用于使用逻辑服务名称/ID 而不是物理 URL 查找服务。Feign 和支持服务发现的 RestTemplate 都利用 Spring Cloud LoadBalancer 进行客户端负载均衡。
如果您想使用 RestTemplate 访问服务 STORES,只需声明
@LoadBalanced
@Bean
public RestTemplate loadbalancedRestTemplate() {
return new RestTemplate();
}
并像这样使用它(注意我们如何使用 Consul 中的 STORES 服务名称/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 是 STORES 服务所在的数据中心。
| Spring Cloud 现在还支持 Spring Cloud LoadBalancer。 |
使用 DiscoveryClient
您也可以使用 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;
}
Consul 目录监控
Consul 目录监控利用了 consul 监控服务 的能力。目录监控发出一个阻塞的 Consul HTTP API 调用,以确定是否有任何服务已更改。如果有新的服务数据,则发布一个心跳事件。
要更改 Config Watch 的调用频率,请更改 spring.cloud.consul.config.discovery.catalog-services-watch-delay。默认值为 1000,以毫秒为单位。延迟是上次调用结束到下次调用开始之间的时间量。
要禁用目录监控,请设置 spring.cloud.consul.discovery.catalogServicesWatch.enabled=false。
该监控使用 Spring TaskScheduler 来调度对 consul 的调用。默认情况下,它是一个 ThreadPoolTaskScheduler,poolSize 为 1。要更改 TaskScheduler,请创建一个类型为 TaskScheduler 且名称为 ConsulDiscoveryClientConfiguration.CATALOG_WATCH_TASK_SCHEDULER_NAME 常量的 bean。