什么是 Service Mesh
想象微服务之间的调用是寄快递:你的服务只管寄件(发请求)和收件(收响应),找地址、保证送达、丢件重发这些事全交给 Service Mesh 处理。
30 秒理解:Service Mesh 给每个服务配一个 Sidecar 代理(通常是 Envoy),代理透明拦截所有网络流量,自动处理服务发现、负载均衡、重试、加密、监控等基础设施能力,让你的业务代码只专注业务逻辑。
Sidecar 是什么:就是在你的应用容器旁边再跑一个代理容器,两个容器共享网络。所有进出你应用的流量都先经过 Sidecar,由它来处理网络复杂性。
前置要求:Service Mesh 通常运行在 Kubernetes 上,如果不了解 K8s,建议先看 k8s-intro。
没有 Service Mesh 的痛点
即使有 K8s Service 解决了服务发现,你的代码还是要处理很多”网络治理”逻辑:
@Controller('order')
export class OrderController {
@Post()
async createOrder(@Body() orderDto: CreateOrderDto) {
// ❌ 要自己实现重试逻辑
let retries = 3;
while (retries > 0) {
try {
const response = await axios.post(
'http://payment-service/pay', // ✅ K8s Service 已解决服务发现
orderDto,
{ timeout: 5000 }
);
return response.data;
} catch (error) {
retries--;
if (retries === 0) throw error;
await sleep(1000); // ❌ 要自己写退避策略
}
}
// ❌ 熔断逻辑要自己实现或引入库(如 Hystrix)
// ❌ mTLS 加密要自己配置证书
// ❌ 分布式追踪要手动传递 TraceID
}
}问题:
- 重试/超时/熔断:每个服务都要写一遍,或引入 SDK(但多语言栈就麻烦了)
- 细粒度流量控制:想做金丝雀发布?K8s Service 做不到按比例路由
- 服务间加密:要手动管理证书、配置 TLS
- 可观测性:要在每个服务里埋点,传递 TraceID,集成监控
- 多语言问题:Java 用 Hystrix,Go 用其他库,Node.js 又是另一套
有了 Service Mesh 之后
@Controller('order')
export class OrderController {
constructor(private readonly paymentClient: PaymentClient) {}
@Post()
async createOrder(@Body() orderDto: CreateOrderDto) {
// ✅ 代码超级简洁,只关心业务逻辑
const result = await this.paymentClient.process(orderDto);
return result;
}
}Sidecar 自动帮你处理:
- ✅ 重试:失败自动重试,可配置次数和退避策略
- ✅ 超时:自动超时控制,不需要在代码里写 timeout
- ✅ 熔断:服务故障自动摘除,避免雪崩
- ✅ 负载均衡:多种策略(轮询/最少连接/权重),比 K8s Service 更灵活
- ✅ mTLS 加密:服务间自动加密通信,零配置
- ✅ 分布式追踪:自动注入 TraceID,无需手动传递
- ✅ 监控指标:自动上报延迟、错误率、流量等指标
- ✅ 语言无关:所有服务享受同样的能力,不管你用什么语言
核心架构
Service Mesh 分为两个平面:
控制平面(Control Plane):管理大脑,下发配置、管理证书、收集遥测数据(如 Istio 的 Istiod)
数据平面(Data Plane):实际干活的 Sidecar 代理(如 Envoy),拦截所有流量
控制平面 (Istiod)
下发配置 ↓ 上报数据 ↑
┌────────┴────────┐
│ │
订单 Pod 支付 Pod
┌────────┐ ┌────────┐
│ 订单服务 │ │ 支付服务 │
│ (App) │ │ (App) │
├────────┤ ├────────┤
│ Envoy │◄────►│ Envoy │
│Sidecar │ 流量 │Sidecar │
└────────┘ └────────┘
关键:Sidecar 透明拦截,应用完全无感知。
Sidecar 如何注入:在 Kubernetes 中,通过给 Namespace 打标签,Istio 会自动在每个 Pod 里注入 Envoy 容器:
# 给 namespace 打标签,启用自动注入
kubectl label namespace default istio-injection=enabled
# 之后部署的所有 Pod 都会自动带上 Envoy Sidecar
kubectl apply -f deployment.yaml典型场景
金丝雀发布
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: payment-route
spec:
http:
- route:
- destination:
host: payment
subset: v1
weight: 90
- destination:
host: payment
subset: v2
weight: 10 # 10% 流量到新版本不改代码,随时调整流量比例,出问题秒回滚。
自动 mTLS
服务 A ─── 明文 HTTP ───→ 服务 B ❌ 不安全
服务 A ─┬─ 应用看到普通 HTTP
└─ Envoy 自动加密 ──→ 服务 B ✅ 自动证书
Istio 自动颁发和轮换证书,零配置。
熔断降级
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
spec:
trafficPolicy:
outlierDetection:
consecutiveErrors: 5
baseEjectionTime: 30s服务故障自动摘除,避免雪崩。
主流方案对比
| 方案 | Istio | Linkerd | Consul Connect |
|---|---|---|---|
| 复杂度 | 高(功能全) | 低(轻量) | 中 |
| 性能损耗 | ~3-5ms | ~1-2ms | ~3-5ms |
| mTLS | ✅ | ✅ | ✅ |
| 多集群 | ✅ 很强 | ✅ 基础 | ✅ |
| 学习曲线 | 陡峭 | 平缓 | 中等 |
建议:新手先用 Linkerd 体验,需要高级功能再迁 Istio。
Service Mesh vs API Gateway
很多人会混淆这两个概念:
| 对比项 | Service Mesh | API Gateway |
|---|---|---|
| 位置 | 服务之间(东西向流量) | 外部到服务(南北向流量) |
| 功能 | 服务间通信治理 | API 聚合、认证、限流 |
| 部署方式 | 每个服务一个 Sidecar | 集中式网关 |
| 典型产品 | Istio、Linkerd | Kong、Nginx、Traefik |
简单记:API Gateway 是”大门口的保安”,Service Mesh 是”每个房间的管家”。两者通常配合使用。
什么时候需要 Service Mesh
| 场景 | 建议 |
|---|---|
| 2-3 个微服务 | ❌ 没必要,用 K8s Service |
| 10+ 微服务,多语言栈 | ✅ 值得考虑 |
| 精细流量控制(金丝雀、A/B) | ✅ 强烈推荐 |
| 服务间必须加密(合规) | ✅ 自动 mTLS 很香 |
| 需要分布式追踪 | ✅ 自动注入 Trace ID |
| 团队小,运维能力弱 | ⚠️ 先上 Linkerd,别碰 Istio |
Service Mesh 能做什么、不能做什么
能做:网络层解耦
| 类型 | 能力 |
|---|---|
| 服务发现 | 不用知道 IP,只写服务名 |
| 负载均衡 | 自动选实例(轮询/最少连接/权重) |
| 流量管理 | 金丝雀、A/B 测试、流量镜像 |
| 安全 | 自动 mTLS、零信任网络 |
| 可观测性 | 自动监控指标、分布式追踪、访问日志 |
| 弹性 | 超时、重试、熔断、限流 |
不能做:业务逻辑解耦
订单服务 ──"下单必须扣款"──► 支付服务
↑ 这是业务规则
Service Mesh 无法消除这个依赖
订单服务还是要调用支付服务,代码里还得写 callPayment()。Service Mesh 只是让调用过程更可靠,不改变调用关系。
真正的业务解耦需要消息队列(Kafka)或事件驱动架构:
订单服务 ─发事件→ 消息队列 ─消费→ 支付服务
(不等响应) (异步处理)
| 方案 | 耦合程度 | 适用场景 |
|---|---|---|
| Service Mesh + 同步 | 松耦合(网络) | 需要实时响应 |
| 消息队列 + 异步 | 更松耦合 | 可异步,最终一致 |