Skip to content

服务发现、健康检查、KV 与 Connect mesh

基于 Consul 1.18 · 核于 2026-08

速查

  • 服务注册:服务启动调 agent service register(或配置文件 service 块),登记 name/id/address/port/tags/check。注册在本地 Client Agent 完成,Agent 转发给 Server 走 Raft 同步。
  • DNS 查询<service>.service.consul 解析出**健康(passing)**实例的 A/AAAA 记录;<service>.service.<dc>.consul 跨 DC;<tag>.<service>.service.consul 按 tag 过滤。端口 8600(默认),SRV 记录含端口。
  • HTTP 查询GET /v1/health/service/:name?passing=true 返回健康实例列表(含 IP/端口/tag/检查状态),SDK 用这个做客户端负载均衡。
  • 健康检查四类型:HTTP(http + interval,2xx=passing)、TCP(tcp,连上即 passing)、Script(args,退出码判定)、TTL(服务主动 agent check pass)。还支持 gRPC(grpc + use_tls)、Docker(docker_container_id)。
  • 三态passing(可查)、warning(可查,软降级)、critical(摘除)。HTTP 检查里 429=warning,5xx=critical。
  • KV 存储:层级化键值(config/db/host),HTTP API GET/PUT/DELETE /v1/kv/:key。支持 CAS(Check-And-Set)(带 cas 参数防并发覆盖)、Watch(长轮询,键变了推送)、Transaction(多 key 原子操作)。
  • Session + Lock:创建 Session(绑定健康检查/TTL)→ 拿到 lock(acquire=true)做领导选举或分布式锁。Session 失效(节点挂/检查 critical)自动释放锁。
  • Connect mesh:Sidecar(consul connect proxy)或原生集成(应用用 Consul API 直接 mTLS)。流量自动 mTLS 加密 + Intentions(白名单授权:service A 能否调 service B)。证书由 Connect CA 自动签发 + 自动轮转。
  • Intentionsconsul intention create -allow web api(允许 web 调 api)、-deny(拒绝)。默认 deny,需显式 allow。Sidecar 在 L4/L7 拦截并校验。

一、服务注册:本地 Agent 接入

服务接入 Consul 的第一步是注册。注册在本地 Client Agent完成(不直连 Server):

json
// 方式 1:配置文件(推荐,Agent 启动时加载,重启自动重注册)
{
  "service": {
    "name": "order-service",
    "id": "order-1",
    "address": "10.0.0.5",
    "port": 8080,
    "tags": ["v1", "primary"],
    "check": {
      "http": "http://localhost:8080/actuator/health",
      "interval": "10s",
      "timeout": "2s",
      "deregister_critical_service_after": "30s"
    }
  }
}
bash
# 方式 2:API 注册(重启后丢失,需应用自己重注册)
curl --request PUT http://127.0.0.1:8500/v1/agent/service/register \
  --data '{"name":"order-service","id":"order-1","address":"10.0.0.5","port":8080,
           "check":{"http":"http://localhost:8080/health","interval":"10s"}}'
  • name vs idname 是服务名(多个实例同名);id 是实例唯一标识(不指定则用 name,多实例必须显式指定 id 避免冲突)。
  • address 省略:省略时用 Agent 所在节点 IP。
  • deregister_critical_service_after:检查 critical 超过该时长后自动反注册(防「死了的实例长期占目录」)。
  • 注册在本地:Agent 把注册信息缓存在本地并转发给 Server。即使 Server 暂时不可达,本地 Agent 仍能服务(恢复后补传)。

二、查询:DNS 与 HTTP 两种入口

DNS 查询(零改造接入)

Consul 内置 DNS 服务器(端口 8600),把「服务名 → 健康实例 IP」直接做成域名解析:

bash
# 1. 基本查询:order-service 的健康实例
dig @127.0.0.1 -p 8600 order-service.service.consul
# → 10.0.0.5, 10.0.0.6, 10.0.0.7(都是 passing 的实例)

# 2. 按 tag 过滤:v1 版本的实例
dig @127.0.0.1 -p 8600 v1.order-service.service.consul

# 3. 跨数据中心
dig @127.0.0.1 -p 8600 order-service.service.dc2.consul

# 4. SRV 记录(含端口)
dig @127.0.0.1 -p 8600 order-service.service.consul SRV
  • 只返回 passing:DNS 默认只解析 passing 状态的实例,warning/critical 自动排除。
  • 轮询负载均衡:DNS 返回的 IP 顺序每次轮转,客户端拿到不同 IP,实现简单轮询。
  • 零改造:非 JVM(Python/Go/老系统)只要把 DNS 指向 Consul,用 order-service.service.consul 当主机名即可,无需 SDK。

HTTP 查询(SDK 精细控制)

SDK 走 HTTP API,能拿到更丰富的信息(tag、检查状态、权重):

bash
# 只看健康实例
curl 'http://127.0.0.1:8500/v1/health/service/order-service?passing=true'
# 返回:[{ "Service": {"Address":"10.0.0.5","Port":8080,...}, "Checks":[...] }, ...]

# 包含所有状态(含 warning/critical)
curl 'http://127.0.0.1:8500/v1/health/service/order-service?passing=false'
  • 客户端负载均衡:SDK(如 Spring Cloud Consul、Consul Template)拿实例列表后自己挑一个发请求(轮询/随机/权重),不走 DNS。
  • ?passing=true 是关键:默认会返回所有状态,加 ?passing=true 才过滤出健康实例。

三、健康检查实战:四类型与三态

健康检查让 Consul 「知道谁还活着」。注册时通过 check 块指定:

json
// HTTP 检查:最常用,探 REST 端点
"check": {
  "http": "http://localhost:8080/actuator/health",
  "interval": "10s",
  "timeout": "2s"
}

// TCP 检查:只看端口通不通(无 HTTP 端点时)
"check": {
  "tcp": "localhost:3306",
  "interval": "10s"
}

// Script 检查:执行脚本(注意 Consul 1.0 后 `script` 改 `args`)
"check": {
  "args": ["/usr/local/bin/check_redis.sh"],
  "interval": "30s"
}

// TTL 检查:服务主动上报
"check": {
  "ttl": "30s"
}
// 服务需周期性调:curl --request PUT http://localhost:8500/v1/agent/check/pass/:check_id
  • HTTP 状态码映射2xxpassing429warning;其他(含 5xx、超时、连接拒绝)→ critical
  • interval 不能太短:HTTP/TCP 检查每 interval 跑一次,太短(如 1s)会压被探服务;太长(如 60s)故障发现慢。经验值 5-15s。
  • TTL 的坑:服务忘了上报会 critical,但 TTL 模式下 Agent 不会主动探——服务卡死但仍在「上报心跳」(心跳线程活着,业务线程死锁)时,TTL 检不出来。所以 TTL 常配合 HTTP 检查双保险。
  • deregister_critical_service_after:实例 critical 超过该时长自动从目录摘除(默认不摘,会一直 critical 占着)。

四、KV 存储:配置、Watch 与分布式锁

KV 是层级化的键值存储,key 用 / 分隔像文件路径:

bash
# 写
curl --request PUT http://127.0.0.1:8500/v1/kv/config/db/host --data '10.0.0.100'

# 读(返回数组,含 Value/base64)
curl http://127.0.0.1:8500/v1/kv/config/db/host

# 带 CAS(防并发覆盖):只有 ModifyIndex 等于给定值才更新
curl --request PUT 'http://127.0.0.1:8500/v1/kv/config/db/host?cas=42' --data '10.0.0.101'

# 列前缀下所有 key
curl 'http://127.0.0.1:8500/v1/kv/config/?recurse=true'

# Watch(长轮询,key 变化时返回)
curl 'http://127.0.0.1:8500/v1/kv/config/db/host?index=42&wait=5m'
  • CAS(Check-And-Set):每个 key 有 ModifyIndex,更新时带 ?cas=<index>,只有 key 当前 index 等于给定值才成功——实现乐观锁,防并发覆盖。
  • Watch 长轮询:带 ?index=<上次 index>&wait=5m,请求会阻塞直到 key 变化(或超时),实现配置推送。consul-template/confd 用这个动态渲染配置文件。
  • Session + 分布式锁(领导选举)
    bash
    # 1. 创建 Session(绑定节点健康检查,节点挂了 Session 自动失效)
    curl --request PUT http://127.0.0.1:8500/v1/session/create \
      --data '{"Name":"leader-election","TTL":"30s","Behavior":"release"}'
    # → {"ID":"sess-xxx"}
    
    # 2. acquire 锁(拿到锁的就是 leader)
    curl --request PUT 'http://127.0.0.1:8500/v1/kv/leader?acquire=sess-xxx' --data 'node-1'
    # → true(抢到)/ false(没抢到)
    
    # 3. 释放(或 Session 失效自动释放)
    curl --request PUT 'http://127.0.0.1:8500/v1/kv/leader?release=sess-xxx'
    Session 绑定健康检查,节点宕机 → Session 失效 → 锁自动释放 → 其他节点能重新 acquire,实现领导选举(谁拿锁谁是主)和分布式锁

五、Connect mesh:mTLS + Intentions

Connect 是 Consul 的服务网格模式,给服务间流量自动加密 + 授权:

   web-app                     api-service
      │                            │
   ┌──┴──────────┐              ┌──┴──────────┐
   │ 本地应用     │              │ 本地应用     │
   │             │              │             │
   │ Sidecar     │ ── mTLS ───→ │ Sidecar     │
   │ (consul     │              │ (consul     │
   │  connect    │              │  connect    │
   │  proxy)     │              │  proxy)     │
   └─────────────┘              └─────────────┘
  • Sidecar 模式:每个服务旁跑一个 consul connect proxy(默认基于 Envoy 或内置 HAProxy),应用把出站流量发给本地 Sidecar,Sidecar 加密后发给目标 Sidecar,目标 Sidecar 解密后转给本地应用。应用无感知
  • 原生集成:应用直接用 Consul API/SDK 自己加 mTLS(不跑 Sidecar),性能更好但需改代码。
  • mTLS 自动化:证书由 Connect CA(内置或接 Vault)自动签发 + 周期性轮转(默认 72 小时),无需手动管证书。
  • Intentions 授权:声明「谁能调谁」:
    bash
    # 允许 web 调 api
    consul intention create -allow web api
    # 拒绝 legacy 调 api
    consul intention create -deny legacy api
    # 查询
    consul intention check web api  # → allowed
    默认策略可设 allow-all 或 deny-all。Sidecar 在连接建立时校验 Intentions,deny 的连接直接拒。
  • 与 Istio 的区别:Consul Connect 是「轻量 mesh」,靠 Consul 自己的目录和 CA,功能比 Istio 少(无高级流量拆分如金丝雀/AB 测试的细粒度权重),但与 Consul 服务发现深度集成,适合已用 Consul 做发现的团队顺手开 mesh。

交互演示

本叶无专门可视化。建议在本机起 Consul(consul agent -dev)后,用 consul catalog list services / dig @127.0.0.1 -p 8600 ... 实操查询。

下一步

理解了四大功能后,下一步看生态与对比——Spring Cloud Consul 的四阶段生命周期、IBM SC-2 参考、与 Nacos/etcd 的横向选型对比。