Consul 服务注册和健康检查
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 代理。开发环境下,可以使用开发模式快速启动一个单节点集群。
- 下载 Consul 对应操作系统的二进制文件,解压并放入系统 PATH 路径下。
- 打开终端,执行以下命令启动开发模式代理:
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 根据检查结果决定是否将服务实例返回给查询者。
常见健康检查类型
-
脚本检查:在代理本地执行一个命令或脚本,根据退出码判断健康状态(0 为健康)。
"check": { "id": "script-check", "name": "Check disk usage", "args": ["/bin/sh", "-c", "/usr/local/bin/check-disk.sh"], "interval": "30s", "timeout": "5s" } -
HTTP 检查:定期向指定 URL 发送 HTTP GET 请求,期待返回 2xx 状态码。
"check": { "id": "http-check", "name": "Health endpoint", "http": "http://localhost:8080/_health", "method": "GET", "interval": "5s", "timeout": "1s" } -
TCP 检查:每隔一定时间尝试建立 TCP 连接,端口可达即认为健康。
"check": { "id": "tcp-check", "name": "SSH port", "tcp": "localhost:22", "interval": "30s", "timeout": "2s" } -
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模式可以手动将服务标记为不可用。 interval和timeout应结合实际业务设定,避免过于频繁的检查导致额外负载。
验证服务健康状态
注册健康检查后,可以通过 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 检查实现自定义健康检测逻辑。
- 引入 Consul 客户端依赖(Maven):
<dependency>
<groupId>com.ecwid.consul</groupId>
<artifactId>consul-api</artifactId>
<version>1.4.5</version>
</dependency>
- 注册服务并创建 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 monitor或journalctl -u consul(systemd 环境)实时跟踪日志。
DNS 解析未返回健康实例
- 确保查询的是
服务名.service.consul且 DNS 端口为 8600。 - 检查服务是否注册到了正确的数据中心(默认
dc1)。
配置不生效
- 确认配置文件格式正确(JSON 或 HCL),且放置在代理可读取的配置目录中。
- 使用
consul validate检查配置文件语法。
总结
Consul 通过简单的服务定义文件和丰富的健康检查机制,为分布式系统提供了坚实的基石。正确配置服务注册与健康检查,意味着你的微服务可以在运行时自动发现健康的依赖服务,实现弹性伸缩与故障转移。建议在生产环境中采用文件注册 + HTTP/TCP 检查的方案,并配合 Consul 的 ACL 和加密通信保障安全。
下一步,可以继续深入学习 Consul 的 KV 存储、配置中心、以及多数据中心部署等高级特性。