Consul 服务注册和健康检查

FreeGuideOnline 最新 2026-07-09

Consul 简介与核心概念

Consul 是 HashiCorp 推出的一个用于实现分布式系统的服务发现、健康检查、KV 存储和多数据中心部署的工具。它为微服务架构中的服务注册、发现和运行时健康监控提供了开箱即用的解决方案。

在开始实践操作前,先理解几个核心概念:

  • 代理(Agent):Consul 集群中的每个节点都需要运行一个代理,它可以以客户端(Client)或服务器(Server)模式运行。服务器负责数据一致性,客户端则负责服务注册与健康检查等本地操作。
  • 服务(Service):一个可通过网络访问的进程,比如 Web 应用、数据库等。服务向 Consul 注册后,就能被其他服务发现。
  • 健康检查(Health Check):用于判断服务实例是否正常运行。Consul 支持多种检查方式,如脚本检查、HTTP 检查、TCP 检查、TTL 检查等。
  • 服务发现(Service Discovery):其他服务可以通过 DNS 或 HTTP API 查询健康的服务实例 IP 和端口。

安装并启动 Consul 代理

在开始服务注册前,需要有一个运行中的 Consul 代理。开发环境下,可以使用开发模式快速启动一个单节点集群。

  1. 下载 Consul 对应操作系统的二进制文件,解压并放入系统 PATH 路径下。
  2. 打开终端,执行以下命令启动开发模式代理:
consul agent -dev

该命令会启动一个本地 Consul 代理,数据存储在内存中,UI 界面默认监听 http://localhost:8500。开发模式下不会有持久化,重启后数据丢失,非常适合实验和学习。

启动成功后,可访问 http://localhost:8500 查看 Web UI。


注册服务到 Consul

服务注册有两种主要方式:通过配置文件定义服务,或者通过 HTTP API 动态注册。推荐使用配置文件方式,便于管理和版本控制。

方式一:使用服务定义文件注册

在 Consul 配置目录下创建一个 json 或 hcl 格式的服务定义文件。例如,创建一个名为 web-service.json 的文件,内容如下:

{
  "service": {
    "name": "web",
    "port": 8080,
    "tags": ["primary", "v1"],
    "check": {
      "id": "web-health",
      "name": "HTTP API on port 8080",
      "http": "http://localhost:8080/health",
      "interval": "10s",
      "timeout": "2s"
    }
  }
}

字段说明:

  • name:服务名称,其他服务通过该名称进行发现。
  • port:服务监听的端口。
  • tags:用于服务筛选和路由的标签列表。
  • check:内嵌的健康检查定义,这里使用 HTTP 检查,Consul 会定期向 http://localhost:8080/health 发送 GET 请求,根据 HTTP 响应状态码判断健康状况(2xx 为健康)。

保存文件后,通过命令行重新加载配置或重新启动 Consul 代理。若代理已启动并监听了配置目录,可以直接复制文件到配置目录(如 consul agent -config-dir=./consul.d)。

注册成功后,在终端运行以下命令查看已注册的服务:

consul catalog services

也可通过 API 查询:

curl http://localhost:8500/v1/catalog/service/web

方式二:使用 HTTP API 注册

也可以通过调用 /v1/agent/service/register 接口动态注册服务,无需重启代理。例如:

curl --request PUT --data '{
  "ID": "web1",
  "Name": "web",
  "Tags": ["primary", "v1"],
  "Address": "localhost",
  "Port": 8080,
  "Check": {
    "HTTP": "http://localhost:8080/health",
    "Interval": "10s"
  }
}' http://localhost:8500/v1/agent/service/register

这种方式在自动扩缩容、动态部署场景中非常有用。


为服务添加健康检查

健康检查是服务发现的核心功能,Consul 根据检查结果决定是否将服务实例返回给查询者。

常见健康检查类型

  1. 脚本检查:在代理本地执行一个命令或脚本,根据退出码判断健康状态(0 为健康)。

    "check": {
      "id": "script-check",
      "name": "Check disk usage",
      "args": ["/bin/sh", "-c", "/usr/local/bin/check-disk.sh"],
      "interval": "30s",
      "timeout": "5s"
    }
    
  2. HTTP 检查:定期向指定 URL 发送 HTTP GET 请求,期待返回 2xx 状态码。

    "check": {
      "id": "http-check",
      "name": "Health endpoint",
      "http": "http://localhost:8080/_health",
      "method": "GET",
      "interval": "5s",
      "timeout": "1s"
    }
    
  3. TCP 检查:每隔一定时间尝试建立 TCP 连接,端口可达即认为健康。

    "check": {
      "id": "tcp-check",
      "name": "SSH port",
      "tcp": "localhost:22",
      "interval": "30s",
      "timeout": "2s"
    }
    
  4. TTL 检查:应用自身必须周期性调用 Consul API 汇报“存活”状态,适合无法被外部探测的应用或防火墙限制场景。

    "check": {
      "id": "ttl-check",
      "name": "Application Heartbeat",
      "ttl": "30s",
      "notes": "Application must update this TTL every 30 seconds"
    }
    

    应用需要调用 PUT /v1/agent/check/pass/{check_id} 来维持健康状态。

定义注意事项

  • 检查可以内联在服务定义中(如上所示),也可以单独定义为独立的检查对象,并关联到服务 ID。
  • 多个检查可以绑定到同一个服务,只有所有检查都通过时,服务才被视为健康。
  • 检查状态除了 passing(健康)、warning(警告)、critical(严重)外,还有 maintenance 模式可以手动将服务标记为不可用。
  • intervaltimeout 应结合实际业务设定,避免过于频繁的检查导致额外负载。

验证服务健康状态

注册健康检查后,可以通过 Consul UI 或命令行观察服务状态。

使用 UI

打开 http://localhost:8500/ui,在 Services 页面中可以看到所有已注册服务,点击具体服务可以查看其健康检查的详细状态和输出。

使用命令行

查看所有服务的健康检查状态:

consul catalog services -tags

查询特定服务下的健康节点:

consul health service web

输出会显示对应的节点地址、端口以及检查状态。也可以通过 API 过滤出仅健康的实例:

curl "http://localhost:8500/v1/health/service/web?passing"

DNS 查询

Consul 提供 DNS 接口,默认监听 8600 端口。可以使用 dig 命令进行服务发现:

dig @127.0.0.1 -p 8600 web.service.consul

只有健康的服务实例才会被返回,这是服务发现中至关重要的特性。


实战:将健康检查整合到 Spring Boot 应用中

这里以 Java 应用为例,演示如何利用 Consul 的 TTL 检查实现自定义健康检测逻辑。

  1. 引入 Consul 客户端依赖(Maven):
<dependency>
    <groupId>com.ecwid.consul</groupId>
    <artifactId>consul-api</artifactId>
    <version>1.4.5</version>
</dependency>
  1. 注册服务并创建 TTL 检查
public class ConsulRegistration {
    public static void main(String[] args) {
        ConsulClient client = new ConsulClient("localhost");
        String serviceId = "my-app-1";

        // 定义服务
        NewService service = new NewService();
        service.setId(serviceId);
        service.setName("my-application");
        service.setPort(8080);
        service.setTags(Arrays.asList("spring", "v2"));

        // 定义 TTL 健康检查
        NewService.Check check = new NewService.Check();
        check.setCheckId("service:" + serviceId);
        check.setTtl("30s");
        check.setNotes("TTL check for my-application");
        service.setCheck(check);

        // 注册服务
        client.agentServiceRegister(service);

        // 定时发送心跳,维持健康状态
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(() -> {
            client.agentCheckPass("service:" + serviceId);
        }, 0, 20, TimeUnit.SECONDS);
    }
}

该示例中,应用每 20 秒向 Consul 汇报一次健康,如果超时未汇报,检查变为 critical,服务也会从健康池中移除。


常见问题与故障排查

服务状态一直为 critical

  • 检查代理能否访问服务提供的健康检查端点(网络、防火墙)。
  • 查看 Consul 代理日志,通常在开发模式下会直接输出到控制台,错误信息会包含具体失败原因。
  • 使用 consul monitorjournalctl -u consul(systemd 环境)实时跟踪日志。

DNS 解析未返回健康实例

  • 确保查询的是 服务名.service.consul 且 DNS 端口为 8600。
  • 检查服务是否注册到了正确的数据中心(默认 dc1)。

配置不生效

  • 确认配置文件格式正确(JSON 或 HCL),且放置在代理可读取的配置目录中。
  • 使用 consul validate 检查配置文件语法。

总结

Consul 通过简单的服务定义文件和丰富的健康检查机制,为分布式系统提供了坚实的基石。正确配置服务注册与健康检查,意味着你的微服务可以在运行时自动发现健康的依赖服务,实现弹性伸缩与故障转移。建议在生产环境中采用文件注册 + HTTP/TCP 检查的方案,并配合 Consul 的 ACL 和加密通信保障安全。

下一步,可以继续深入学习 Consul 的 KV 存储、配置中心、以及多数据中心部署等高级特性。