mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1416 字
4 分钟
服务发现:微服务通信的基础设施
2025-03-09

某电商系统从单体架构拆分为 50 个微服务,每个服务部署 3-10 个实例,实例 IP 随容器调度频繁变化。订单服务需要调用库存服务的接口,但库存服务的 IP 每天可能变化数次——硬编码 IP 显然不可行。服务发现机制让服务消费者动态感知服务提供者的地址变化,是微服务通信的基础设施。

一、为什么需要服务发现#

1.1 单体架构 vs 微服务架构#

在单体架构中,模块间通过函数调用通信,地址在编译期确定。微服务架构中,服务实例动态变化:

  • 容器调度导致 IP 频繁变化
  • 弹性伸缩导致实例数量动态增减
  • 故障恢复导致实例替换

1.2 服务发现的核心需求#

需求描述
注册服务实例启动时将自己的地址告知注册中心
发现消费者从注册中心获取提供者的地址列表
健康检查注册中心定期检查实例是否存活
通知实例状态变化时通知消费者

二、服务发现模式#

2.1 客户端发现(Client-Side Discovery)#

消费者直接查询注册中心,自行选择实例:

graph LR A[服务消费者] -->|查询| B[注册中心] B -->|返回实例列表| A A -->|直接调用| C[服务实例1] A -->|直接调用| D[服务实例2]

优点:

  • 客户端可自定义负载均衡策略
  • 无需中间代理,延迟更低

缺点:

  • 客户端与注册中心耦合
  • 每种语言需实现服务发现客户端

典型实现:Netflix Eureka + Ribbon、Nacos。

2.2 服务端发现(Server-Side Discovery)#

消费者通过负载均衡器间接访问服务实例:

graph LR A[服务消费者] -->|请求| B[负载均衡器] B -->|查询| C[注册中心] B -->|转发| D[服务实例1] B -->|转发| E[服务实例2]

优点:

  • 客户端无需感知服务发现逻辑
  • 与语言无关

缺点:

  • 负载均衡器是额外组件
  • 增加一跳延迟

典型实现:Kubernetes Service + kube-proxy、AWS ALB。

2.3 两种模式对比#

维度客户端发现服务端发现
负载均衡客户端实现负载均衡器实现
客户端复杂度
语言依赖
额外组件负载均衡器
延迟多一跳

三、注册中心实现#

3.1 核心数据模型#

注册中心存储的是服务实例的元数据:

服务名: inventory-service
实例列表:
- 10.0.1.10:8080 weight=100 status=UP
- 10.0.1.11:8080 weight=100 status=UP
- 10.0.1.12:8080 weight=50 status=UP
元数据:
- region: cn-east
- zone: zone-a
- version: v2.1.0

3.2 注册与发现流程#

sequenceDiagram participant P as 服务提供者 participant R as 注册中心 participant C as 服务消费者 P->>R: 注册实例(IP、端口、元数据) P->>R: 发送心跳 C->>R: 订阅服务变更 R-->>C: 推送实例列表 C->>P: 发起调用

3.3 健康检查#

模式原理优缺点
客户端心跳实例定期发送心跳简单,但无法检测假死
服务端探活注册中心主动探测准确,但增加注册中心负担
应用层探活检查应用特定接口最准确,但需定义探活接口

四、主流注册中心对比#

维度EurekaConsulNacosZooKeeper
一致性APCP(默认)AP/CP 可选CP
健康检查客户端心跳TCP/HTTP/gRPCTCP/HTTP/MySQL会话保持
配置管理
多数据中心
访问协议HTTPHTTP/DNSHTTP/gRPCTCP
Spring Cloud原生支持原生支持原生支持原生支持

4.1 Eureka#

Netflix 开源的 AP 注册中心,优先保证可用性:

// Eureka 客户端配置
eureka:
client:
serviceUrl:
defaultZone: http://eureka1:8761/eureka/,http://eureka2:8761/eureka/
registryFetchIntervalSeconds: 30
instance:
leaseRenewalIntervalInSeconds: 10
leaseExpirationDurationInSeconds: 90

特点:

  • 自我保护模式:心跳比例低于阈值时不再剔除实例
  • Peer-to-Peer 复制:节点间异步复制,最终一致
  • 适合 AWS 等云环境

4.2 Nacos#

阿里开源的注册中心,支持 AP/CP 切换:

// Nacos 客户端配置
spring:
cloud:
nacos:
discovery:
server-addr: nacos1:8848,nacos2:8848
namespace: production
group: DEFAULT_GROUP
cluster-name: SH

特点:

  • 临时实例走 AP 模式(Distro 协议),永久实例走 CP 模式(Raft 协议)
  • 支持配置管理和服务发现一体化
  • 支持权重路由和就近路由

4.3 Consul#

HashiCorp 开源的 CP 注册中心:

# Consul 服务定义
service {
name = "inventory-service"
port = 8080
tags = ["v2.1.0"]
check {
http = "http://localhost:8080/health"
interval = "10s"
timeout = "1s"
}
}

特点:

  • 支持 DNS 接口,方便非微服务应用接入
  • 内置多数据中心支持
  • 提供 KV 存储、服务网格等功能

五、负载均衡策略#

服务发现获取实例列表后,需要选择一个实例发起调用:

策略原理适用场景
Round Robin(轮询)依次选择实例性能相近
Random(随机)随机选择实例性能相近
Weighted Round Robin(加权轮询)按权重分配实例性能不均
Least Connections(最少连接)选择连接数最少的长连接场景
Consistent Hash(一致性哈希)相同请求路由到同一实例有状态服务
Zone Aware(区域感知)优先同区域实例多区域部署

六、服务发现与 Kubernetes#

Kubernetes 内置了服务发现机制:

6.1 Service 资源#

apiVersion: v1
kind: Service
metadata:
name: inventory-service
spec:
selector:
app: inventory
ports:
- port: 80
targetPort: 8080
type: ClusterIP

6.2 DNS 发现#

Kubernetes 集群内通过 CoreDNS 提供服务发现:

inventory-service.default.svc.cluster.local

6.3 Endpoint 维护#

kube-proxy 监控 Endpoint 变化,更新 iptables/IPVS 规则:

Service: inventory-service → 10.0.1.10:8080, 10.0.1.11:8080, 10.0.1.12:8080

七、实践建议#

  1. 注册中心高可用:至少部署 3 个节点,跨可用区分布
  2. 合理配置心跳:心跳间隔和超时时间需要根据网络环境调整
  3. 优雅上下线:服务下线前先从注册中心注销,避免请求打到已停止的实例
  4. 本地缓存:消费者缓存实例列表,注册中心不可用时仍可调用
  5. 元数据丰富:利用元数据实现灰度发布、就近路由等高级功能
// 优雅下线示例
@PreDestroy
public void gracefulShutdown() {
// 1. 从注册中心注销
registry.deregister(instance);
// 2. 等待在途请求完成
Thread.sleep(5000);
// 3. 关闭服务
server.stop();
}

服务发现是微服务架构的基础设施,选择合适的注册中心和发现模式,是构建可靠微服务系统的第一步。理解不同注册中心的 CP/AP 取舍,以及客户端发现与服务端发现的差异,才能根据业务场景做出正确选择。

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

服务发现:微服务通信的基础设施
https://blog.souloss.com/posts/distributed/distributed-service-discovery/
作者
Souloss
发布于
2025-03-09
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时