66. 使用 Consul 进行服务发现

Service Discovery 是基于微服务的 architecture 的 key 原则之一。尝试手动配置每个 client 或某种形式的约定可能非常难以做到并且可能非常脆弱。 Consul 通过HTTP APIDNS提供服务发现服务。 Spring Cloud Consul 利用 HTTP API 进行服务注册和发现。这并不妨碍 non-Spring Cloud Applications 利用 DNS 接口。 Consul Agents 服务器在中运行,通过八卦协议进行通信并使用筏共识协议

66.1 如何激活

要激活 Consul Service Discovery,请使用带有 group org.springframework.cloud和 artifact id spring-cloud-starter-consul-discovery的 starter。有关使用当前 Spring Cloud Release Train 设置 build 系统的详细信息,请参阅Spring Cloud 项目页面

66.2 注册 Consul

当 client 向 Consul 注册时,它提供 meta-data 关于自身,例如 host 和 port,id,name 和 tags。默认情况下会创建 HTTP 校验,Consul 每 10 秒命中一次/health端点。如果运行状况检查失败,则将服务实例标记为严重。

Example Consul client:

@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);
    }

}

(i.e.完全正常 Spring Boot 应用程序)。如果 Consul client 位于localhost:8500以外的其他位置,则需要 configuration 来定位 client。 例:

application.yml.

spring:
  cloud:
    consul:
      host: localhost
      port: 8500

如果使用Spring Cloud Consul Config,则需要将上述值放在bootstrap.yml而不是application.yml中。

Environment获取的默认服务 name,instance id 和 port 分别是${spring.application.name},Spring Context ID 和${server.port}

要禁用 Consul Discovery Client,您可以将spring.cloud.consul.discovery.enabled设置为false

要禁用服务注册,您可以将spring.cloud.consul.discovery.register设置为false

66.3 HTTP 运行状况检查

Consul 实例的运行状况检查默认为“/health”,这是 Spring Boot Actuator application 中有用端点的默认位置。如果使用 non-default context 路径或 servlet 路径(e.g. server.servletPath=/foo)或 management 端点路径(e.g. management.server.servlet.context-path=/admin),则需要更改这些,即使对于 Actuator application 也是如此。还可以配置 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来禁用运行状况检查。

66.3.1 元数据和 Consul 标记

Consul 尚不支持服务元数据。 Spring Cloud 的ServiceInstance有一个Map<String, String> metadata字段。 Spring Cloud Consul 使用 Consul 标签来近似元数据,直到 Consul 正式支持元数据。具有key=value形式的标签将被拆分并分别用作Map key 和 value。没有相同=符号的标签将同时用作 key 和 value。

application.yml.

spring:
  cloud:
    consul:
      discovery:
        tags: foo=bar, baz

上面的 configuration 将导致带有foo→barbaz→baz的 map。

66.3.2 使 Consul 实例 ID 唯一

默认情况下,consul 实例注册的 ID 等于其 Spring Application Context ID。默认情况下,Spring Application Context ID 为${spring.application.name}:comma,separated,profiles:${server.port}。对于大多数情况,这将允许一台服务的多个实例在一台机器上运行。如果需要进一步的唯一性,使用 Spring Cloud 可以通过在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 上部署了多个服务实例,随机 value 将在那里启动以使该实例唯一。在 Cloudfoundry 中,vcap.application.instance_id将自动填充在 Spring Boot application 中,因此不需要随机 value。

66.4 查找服务

66.4.1 使用 Ribbon

Spring Cloud 支持假装(REST 客户端构建器),也支持Spring RestTemplate使用逻辑服务 names/ids 而不是物理 URL 查找服务。 Feign 和 discovery-aware RestTemplate 都使用进行 client-side 负载平衡。

如果要使用 RestTemplate 访问服务 STORES,只需声明:

@LoadBalanced
@Bean
public RestTemplate loadbalancedRestTemplate() {
     new RestTemplate();
}

并像这样使用它(注意我们如何使用来自 Consul 的 STORES 服务 name/id 而不是完全限定的域名):

@Autowired
RestTemplate restTemplate;

public String getFirstProduct() {
   return this.restTemplate.getForObject("https://STORES/products/1", String.class);
}

如果您在多个数据中心中有 Consul 群集,并且您想要访问另一个数据中心中的服务,则仅服务 name/id 是不够的。在这种情况下,您使用 property spring.cloud.consul.discovery.datacenters.STORES=dc-west,其中STORES是服务 name/id,dc-west是 STORES 服务所在的数据中心。

66.4.2 使用 DiscoveryClient

您还可以使用org.springframework.cloud.client.discovery.DiscoveryClient为发现客户端提供一个简单的 API,该 API 不是特定于 Netflix,e.g.

@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;
}

66.5 Consul Catalog Watch

Consul 目录 Watch 利用 consul watch 服务的能力。 Catalog Watch 进行阻塞 Consul HTTP API 调用以确定是否有任何服务已更改。如果有新的服务数据,则发布 Heartbeat Event。

要更改调用 Config Watch 的频率,请更改spring.cloud.consul.config.discovery.catalog-services-watch-delay。默认的 value 是 1000,以毫秒为单位。延迟是上一次调用结束和下一次调用开始后 time 的数量。

要禁用 Catalog Watch set spring.cloud.consul.discovery.catalogServicesWatch.enabled=false

watch 使用 Spring TaskScheduler来安排对 consul 的调用。默认情况下,它是一个ThreadPoolTaskScheduler,其poolSize为 1.要更改TaskScheduler,请创建一个ConsulDiscoveryClientConfiguration.CATALOG_WATCH_TASK_SCHEDULER_NAME类型