
服务少的时候,可以在配置里直接写地址。实例多起来,地址会变,某个实例还可能暂时不可用,这时就需要一个地方记录“这个服务现在有哪些实例”。Consul 可以提供服务注册、发现和健康检查等能力。
1、注册和发现是什么?
- 注册:把实例 ID、服务名、地址和端口告诉 Consul。
- 发现:按服务名查询符合条件的实例,再选择一个进行调用。
- 健康检查:记录实例状态,让调用方能够过滤异常实例。
“已注册”和“业务可用”要分开。消费者要查询健康状态,而且调用仍然需要超时和错误处理;健康检查不能保证下一次请求必然成功。相关接口见 Health API。
2、安装和启动
这里用 Docker 启动一个本地开发实例。示例固定在 1.21.3,方便对照旧学习环境,不代表推荐生产环境停留在该版本。
docker run -d \
--name dev-consul \
-p 127.0.0.1:8500:8500 \
hashicorp/consul:1.21.3 agent -dev -client=0.0.0.0
浏览器访问 http://127.0.0.1:8500。-dev 是开发模式,退出后不能依靠它保存生产状态。容器里监听所有地址,是为了让端口映射能访问;宿主机映射仍然限制在本地。


3、在 Go 中完成一次注册与发现
先在新的示例目录初始化模块:
go mod init example.com/consul-demo
下面保存为 main.go,再执行后面的依赖安装指令。
package main
import (
"fmt"
"net/http"
"os"
"time"
"github.com/hashicorp/consul/api"
)
func run() error {
cfg := api.DefaultConfig()
cfg.Address = "127.0.0.1:8500"
cfg.HttpClient = &http.Client{Timeout: 3 * time.Second}
client, err := api.NewClient(cfg)
if err != nil {
return err
}
registration := &api.AgentServiceRegistration{
ID: "demo-api-1", Name: "demo-api",
Address: "127.0.0.1", Port: 18080,
Check: &api.AgentServiceCheck{TTL: "15s"},
}
if err := client.Agent().ServiceRegister(registration); err != nil {
return err
}
defer func() {
if err := client.Agent().ServiceDeregister(registration.ID); err != nil {
fmt.Println("注销失败:", err)
}
}()
if err := client.Agent().UpdateTTL("service:demo-api-1", "demo heartbeat", "passing"); err != nil {
return err
}
services, _, err := client.Health().Service("demo-api", "", true, nil)
if err != nil {
return err
}
for _, entry := range services {
fmt.Printf("%s %s:%d\n", entry.Service.ID, entry.Service.Address, entry.Service.Port)
}
return nil
}
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, "Consul 示例失败:", err)
os.Exit(1)
}
}
保存代码后,安装示例使用的 SDK 版本并运行:
go get github.com/hashicorp/consul/api@v1.30.0
go mod tidy
go run .
这个版本用于复现上面的 API 示例;后续更换版本时重新验证,并保留 go.mod 和 go.sum。程序演示“注册 → 更新 TTL 心跳 → 查询健康实例 → 退出时注销”。它没有启动 18080 上的真实业务服务,地址只是示例元数据;打印出地址不等于业务接口已经可用了。Go SDK 接口与服务注册 API可以对照着看。
真正接到应用里,先启动业务服务,再注册可达地址。TTL 心跳要周期性更新,并且结合自己的状态决定报 passing 还是 critical;如果希望 Consul 主动检查接口,可以换成 HTTP 检查,确认 Consul agent 能访问对应地址。
4、容易踩的坑
服务名和实例 ID 不一样。多个实例可以都叫 demo-api,但 ID 应该各不相同,否则会覆盖注册信息。
地址是给消费者用的。这里的 127.0.0.1 只适合同一台宿主机上的调用方。跨机器或跨容器调用时,要注册调用方实际能访问的地址。
注销不是故障处理的全部。正常退出可以注销,进程被强制结束时还要依靠健康检查。发现时查询健康实例,调用时继续处理超时与连接失败。
KV 存储也不是随便换个数据库。可以用于配置等场景,但要考虑权限、更新通知和读取失败时的行为。