68. Consul 服务发现
服务发现是基于微服务的体系结构的关键原则之一。尝试手动配置每个 Client 端或某种形式的约定可能非常困难并且非常脆弱。Consul 通过HTTP API和DNS提供服务发现服务。 Spring Cloud Consul 利用 HTTP API 进行服务注册和发现。这不会阻止非 Spring Cloud 应用程序利用 DNS 接口。 Consul Agents 服务器在cluster中运行,该cluster通过gossip protocol进行通信并使用筏共识协议。
68.1 如何激活
要激活 Consul Service Discovery,请使用带有org.springframework.cloud
组和工件 ID spring-cloud-starter-consul-discovery
的启动器。有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参见Spring Cloud Project 页面。
68.2 向 Consul 注册
当 Client 端向 Consul 注册时,它将提供有关其自身的元数据,例如主机和端口,id,名称和标签。默认情况下会创建一个 HTTP Check,Consul 每 10 秒会命中一次/health
端点。如果运行状况检查失败,则将该服务实例标记为关键。
ConsulClient 端示例:
@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 应用)。如果 ConsulClient 端位于localhost:8500
以外的其他位置,则需要进行配置才能找到该 Client 端。例:
application.yml.
spring:
cloud:
consul:
host: localhost
port: 8500
Warning
如果您使用Spring Cloud Consul 配置,则需要将上述值放在bootstrap.yml
而不是application.yml
中。
来自Environment
的默认服务名称,实例 ID 和端口分别是${spring.application.name}
,Spring Context ID 和${server.port}
。
要禁用 Consul Discovery Client,可以将spring.cloud.consul.discovery.enabled
设置为false
。
要禁用服务注册,可以将spring.cloud.consul.discovery.register
设置为false
。
68.2.1 将 Management 注册为单独的服务
当 Management 服务器端口设置为与应用程序端口不同时,通过设置management.server.port
属性,Management 服务将被注册为与应用程序服务不同的服务。例如:
application.yml.
spring:
application:
name: myApp
management:
server:
port: 4452
以上配置将注册以下两项服务:
- Application Service:
ID: myApp
Name: myApp
- Management Service:
ID: myApp-management
Name: myApp-management
Management 服务将从应用程序服务继承其instanceId
和serviceName
。例如:
application.yml.
spring:
application:
name: myApp
management:
server:
port: 4452
spring:
cloud:
consul:
discovery:
instance-id: custom-service-id
serviceName: myprefix-${spring.application.name}
以上配置将注册以下两项服务:
- 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
68.3 HTTP 运行状况检查
Consul 实例的运行状况检查默认为“/health”,这是 Spring Boot Actuator 应用程序中有用端点的默认位置。即使您使用非默认上下文路径或 Servlet 路径(例如server.servletPath=/foo
)或 Management 端点路径(例如management.server.servlet.context-path=/admin
),也需要更改这些内容,即使对于 Actuator 应用程序也是如此。还可以配置 Consul 用于检查运行状况终结点的时间间隔。 “ 10s”和“ 1m”分别代表 10 秒和 1 分钟。例:
application.yml.
spring:
cloud:
consul:
discovery:
healthCheckPath: ${management.server.servlet.context-path}/health
healthCheckInterval: 15s
您可以通过设置management.health.consul.enabled=false
禁用运行状况检查。
68.3.1 元数据和 Consul 标签
Consul 尚不支持有关服务的元数据。 Spring Cloud 的ServiceInstance
有一个Map<String, String> metadata
字段。 Spring Cloud Consul 使用 Consul 标签来近似元数据,直到 Consul 正式支持元数据。格式为key=value
的标签将被拆分并分别用作Map
键和值。没有等号=
的标记将用作键和值。
application.yml.
spring:
cloud:
consul:
discovery:
tags: foo=bar, baz
上面的配置将生成带有foo→bar
和baz→baz
的 Map。
68.3.2 使 Consul 实例 ID 唯一
默认情况下,Consul 实例的 ID 等于其 Spring Application Context ID。默认情况下,Spring Application Context ID 为${spring.application.name}:comma,separated,profiles:${server.port}
。在大多数情况下,这将允许一项服务的多个实例在一台计算机上运行。如果需要进一步的唯一性,则可以使用 Spring_spring.cloud.consul.discovery.instanceId
中提供一个唯一的标识符来覆盖它。例如:
application.yml.
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 应用程序中,因此将不需要随机值。
68.3.3 将 Headers 应用于健康检查请求
Headers 可以应用于健康检查请求。例如,如果您尝试注册使用Vault Backend的Spring Cloud Config服务器:
application.yml.
spring:
cloud:
consul:
discovery:
health-check-headers:
X-Config-Token: 6442e58b-d1ea-182e-cfa5-cf9cddef0722
根据 HTTP 标准,每个 Headers 可以有多个值,在这种情况下,可以提供一个数组:
application.yml.
spring:
cloud:
consul:
discovery:
health-check-headers:
X-Config-Token:
- "6442e58b-d1ea-182e-cfa5-cf9cddef0722"
- "Some other value"
68.4 查找服务
68.4.1 使用功能区
Spring Cloud 支持Feign(RESTClient 端构建器),也支持Spring RestTemplate使用逻辑服务名称/标识而不是物理 URL 查找服务。 Feign 和可发现发现的 RestTemplate 都使用Ribbon进行 Client 端负载平衡。
如果要使用 RestTemplate 访问服务 STORES,只需声明:
@LoadBalanced
@Bean
public RestTemplate loadbalancedRestTemplate() {
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 服务所在的数据中心。
68.4.2 使用 DiscoveryClient
您也可以使用org.springframework.cloud.client.discovery.DiscoveryClient
,它为发现 Client 端提供了一个简单的 API,该 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;
}
68.5Consul 目录手表
Consul 目录监视利用 Consulwatch services的能力。 Catalog Watch 进行了阻塞的 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 的调用。缺省情况下,它是poolSize
为 1 的ThreadPoolTaskScheduler
。要更改TaskScheduler
,请创建一个TaskScheduler
类型的 Bean,该 Bean 以ConsulDiscoveryClientConfiguration.CATALOG_WATCH_TASK_SCHEDULER_NAME
常量命名。