本页目录
服务发现
在动态扩缩的集群里,调用方怎么知道该连哪个 IP?服务发现把"注册→健康检查→查询"做成标准流程:consul/etcd 存注册表,DNS-SD 和客户端负载均衡是两种不同的查询路径,health check 决定"这个实例还能不能接流量"。
问题
服务实例的 IP:port 是动态变化的(扩缩容、滚动更新、故障迁移)。调用方如何知道"现在有哪些实例可用"?
DNS-SD (Service Discovery via DNS)
利用成熟的 DNS 基础设施做服务发现:
服务: api-service → DNS SRV records:
_api._tcp.example.com SRV 10 60 8080 instance-1.example.com
_api._tcp.example.com SRV 10 40 8080 instance-2.example.com
client: dig SRV _api._tcp.example.com → [instance-1:8080, instance-2:8080]
优势:无需额外组件。局限:DNS TTL 决定变更延迟(通常 30-60s),没有原生健康检查。
Consul/etcd 服务注册
服务实例启动 → register to Consul/etcd (with health check URL) → client 查询 → 返回 healthy instances:
支持:HTTP API、DNS 接口(兼容 DNS-SD)、long-poll watch(变更推)。
Client-side vs Server-side LB
Client-side:
[Client] → 查询服务发现 → 得到 [I1, I2, I3] → 自己选一个 → 直连
例子: gRPC (with Consul/etcd resolver), Finagle, netflix-eureka
Server-side:
[Client] → LB (固定地址) → LB → [I1, I2, I3]
例子: kube-proxy, nginx upstream, HAProxy
对比:client-side 少一跳(latency↓),但 client 要维护服务发现逻辑。Server-side client 无需感知后端变化,但 LB 成为瓶颈和单点。
Health Check
- Passive: 从实际请求的 failure(HTTP 5xx, TCP RST)判断。不需要额外请求,但可能被偶尔的 transient error 误判
- Active: 定期 GET /health → 期望 200。可靠但增加负载
- TTL-based (Consul): agent 定期向 Consul 报告健康状态。超时未收到 report → 标记 unhealthy → 从发现中移除
参考
- Consul: consul.io/docs/discovery
- etcd: etcd.io/docs
- gRPC name resolution: github.com/grpc/grpc/blob/master/doc/naming.md
Keywords: service discovery, DNS-SD, Consul, etcd, health check, client-side LB, server-side LB