This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/hzh/MS/02-服务治理/04-服务发现.md
T
2026-05-15 16:26:14 +08:00

206 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [microservice, service-discovery, consul, nacos, etcd, kubernetes]
create time: 2026-05-05
---
# 服务发现
## 概述
服务实例的动态变化(扩容、缩容、故障重启)让硬编码地址成为不可能。服务要回答的核心问题是:**我怎么找到你?**
> [!question] 引出问题
> 假设你的订单服务有 3 个实例,运行在 `10.0.1.1:8080`、`10.0.1.2:8080`、`10.0.1.3:8080`。当其中一个实例扩容下线时,调用方如何得知最新的地址列表?手动改配置滚动重启?还是……有更好的办法?
## 两种发现模式
```mermaid
graph TB
subgraph Client["客户端发现模式"]
A[Service A] -->|1.查询注册中心| R1[(Registry)]
R1 -->|2.返回实例列表| A
A -->|3.自选实例直连| B[Service B]
noteA[客户端内置负载均衡逻辑]
end
subgraph Server["服务端发现模式"]
C[Service C] -->|请求| P[LoadBalancer Proxy]
P -->|查询注册中心| R2[(Registry)]
R2 -->|返回实例| P
P -->|转发| D[Service D]
noteC[客户端无感知,透明代理]
end
```
**对比**:
| 维度 | 客户端发现 | 服务端发现 |
|------|-----------|-----------|
| 典型实现 | Eureka、Consul、Nacos | Nginx、Envoy、K8s Service |
| 耦合度 | 客户端嵌入注册逻辑 | 透明代理,客户端无感知 |
| 性能 | 直连调用,延迟最低 | 多一跳代理开销 |
| 运维复杂度 | 每门语言需独立 SDK | 统一部署代理,技术无关 |
| 灵活性 | 客户端可自定义路由策略 | 受限于代理能力 |
### 客户端发现的优劣势分析
**优势**:
- 直连调用,少了一跳网络开销
- 客户端可以根据本地缓存做智能选择(如就近节点优先)
- 框架成熟,Eureka/Consul 社区案例丰富
**劣势**:
- 每个服务实现中都需要集成 SDK,跨语言迁移成本高
- 客户端需要处理实例列表的缓存与刷新逻辑
- 新增服务时需要修改调用方的代码或配置
### 服务端发现的优劣势分析
**优势**:
- 完全解耦——调用方只需知道 Proxy 地址
- 统一治理入口,可以在代理层加限流、熔断等逻辑
- 适合多语言团队,无需各自维护 SDK
**劣势**:
- 额外一跳增加延迟(通常 <1ms,高吞吐场景累积明显)
- Proxy 本身成为单点瓶颈,必须做横向扩展
- 调测复杂度上升——出了问题要看两层日志
## 主流注册中心选型
### Nacos(推荐国内团队首选)
阿里开源,支持 AP(临时实例)+ CP(持久实例)双模型,同时提供配置管理功能。
```go
// Nacos 服务注册 & 拉取
import (
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
)
// 创建注册客户端
sc := constant.ServerConfig{
IpAddr: "127.0.0.1",
Port: 8848,
}
// 注册服务实例
client, _ := clients.NewNamingClient(
value_map.NewValueMap(map[string]any{"serverConfig": sc}),
)
client.RegisterInstance(naming_param.RegisterInstanceParam{
Ip: "10.0.0.1",
Port: 8080,
ServiceName: "order-service",
ClusterName: "DEFAULT",
})
// 拉取某服务的可用实例列表
instances, _ := client.SelectInstances(naming_param.SelectInstanceParam{
ServiceName: "order-service",
})
```
### Consul
HashiCorp 出品,基于 Raft 共识协议(CP),天然支持健康检查和 DNS 接口。
**核心特点**:
- 内建 KV 存储,可作为轻量配置中心
- 支持 multi-datacenter 部署
- DNS 接口:`order-service.service.consul` 可直接解析 IP
### etcd + K8s Service
纯容器环境下最自然的选择。etcd 存数据,K8s 提供完整的发现和负载均衡体系。
```yaml
# K8s Service — 服务端发现模式的代表
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order
ports:
- port: 80
targetPort: 8080
type: ClusterIP
```
调用方只需 `http://order-service:80`,K8s 通过 iptables/IPVS 自动实现负载均衡。
### Eureka
Netflix 开源,AP 模型。**注意**:Eureka 2.x 已开源关闭,不建议新项目使用。已有系统在迁移到 Nacos 或 Consul 之前可以继续用。
## 关键机制
### 服务注册流程
```mermaid
sequenceDiagram
participant S as 服务实例
participant R as 注册中心
participant H as 健康检查器
S->>R: 1. Register(instance)
R-->>S: 2. ACK
Note over S,R: 实例写入内存 / etcd
loop 定时心跳
S->>R: 3. Heartbeat (每 5s)
R-->>S: 4. ACK
end
R->>H: 5. 超过心跳间隔未收到 → 标记不健康
H->>R: 6. 摘除实例
```
### 临时实例 vs 持久实例
| 类型 | 宕机检测方式 | 数据存储 | 适用场景 |
|------|-------------|---------|---------|
| **临时实例 (ephemeral)** | 心跳超时自动摘除 | 内存 | Web 服务、应用实例 |
| **持久实例 (persistent)** | 主动注销才摘除 | etcd | 数据库连接、外部依赖 |
> [!warning] 常见陷阱
> 把数据库当成临时实例注册 —— 数据库挂了不需要被 "检测到",它自己控制启停。应该用持久实例。
### 优雅上下线
服务下线时不能直接断网,否则正在处理的请求会失败。
**上线流程**:
1. 进程启动 → 加载配置、初始化连接池
2. `/ready` 探针返回 200 → 注册中心注册 + K8s 加入负载均衡池
3. 开始接收流量
**下线流程**:
1. 注册中心注销实例 → 停止接收新请求
2. 等待正在处理的请求完成(最大等待 N 秒)
3. 关闭连接池、保存状态
4. 进程退出
> [!tip] K8s Pod 优雅终止
> ```yaml
> spec:
> terminationGracePeriodSeconds: 30 # 最多等 30 秒再 SIGKILL
> ```
> 配合 `preStop` Hook 可以提前摘除流量:
> ```yaml
> lifecycle:
> preStop:
> exec:
> command: ["sh", "-c", "sleep 15"] # 给负载均衡摘流的时间
> ```
## 关联笔记
- [[02-服务治理/01-API网关]] — API Gateway 是服务发现的用户之一
- [[02-服务治理/06-容错模式]] — 健康检查是容错体系的基础
- [[05-部署运维/02-Kubernetes]] — K8s Service 的服务发现原理