Architecture · #service-mesh#istio#envoy

Service Mesh与Istio实战指南

2025.05.23 7 min 2.6k
// 目录 · contents

前言

在微服务架构中,服务间的通信变得日益复杂——负载均衡、服务发现、超时重试、熔断降级、安全认证、链路追踪,这些横切关注点如果由每个服务自行实现,将导致大量重复代码和不一致的行为。Service Mesh 通过将这些功能下沉到基础设施层来解决这个问题。Istio 是目前最成熟的 Service Mesh 实现,本文将深入解析其架构原理和实战用法。

Service Mesh 概述

什么是 Service Mesh

Service Mesh(服务网格)是一个用于处理服务间通信的基础设施层。它通过在每个服务实例旁部署一个代理(Sidecar),接管所有的入站和出站网络流量。

graph TB
    subgraph "无 Service Mesh"
        A1[服务 A<br/>含通信逻辑] -->|直接调用| B1[服务 B<br/>含通信逻辑]
        A1 --> C1[服务 C<br/>含通信逻辑]
    end

    subgraph "有 Service Mesh"
        A2[服务 A] <--> PA[Sidecar Proxy]
        B2[服务 B] <--> PB[Sidecar Proxy]
        C2[服务 C] <--> PC[Sidecar Proxy]

        PA <-->|mTLS| PB
        PA <-->|mTLS| PC
        PB <-->|mTLS| PC
    end

Sidecar 模式

Sidecar 代理与应用容器部署在同一个 Pod 中,拦截所有进出应用的网络流量。应用无需修改任何代码。

graph LR
    subgraph Pod
        App[应用容器<br/>:8080] <-->|localhost| Proxy[Envoy Sidecar<br/>:15001]
    end

    External[外部流量] --> Proxy
    Proxy --> OtherPod[其他服务]

    Note1[iptables 规则将<br/>所有流量重定向到 Envoy]

流量拦截通过 iptables 规则实现:

1
2
3
4
5
6
7
8
9
# Istio 注入的 iptables 规则(简化版)
# 将所有出站流量重定向到 Envoy 的 15001 端口
iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to-port 15001

# 将所有入站流量重定向到 Envoy 的 15006 端口
iptables -t nat -A PREROUTING -p tcp -j REDIRECT --to-port 15006

# 排除 Envoy 自身的流量,避免死循环
iptables -t nat -A OUTPUT -m owner --uid-owner 1337 -j RETURN

Istio 架构

控制平面与数据平面

graph TB
    subgraph 控制平面 Control Plane
        Istiod[Istiod]
        Istiod --> Pilot[Pilot<br/>流量管理]
        Istiod --> Citadel[Citadel<br/>安全/证书]
        Istiod --> Galley[Galley<br/>配置验证]
    end

    subgraph 数据平面 Data Plane
        subgraph Pod A
            AppA[App A] <--> EnvoyA[Envoy]
        end
        subgraph Pod B
            AppB[App B] <--> EnvoyB[Envoy]
        end
        subgraph Pod C
            AppC[App C] <--> EnvoyC[Envoy]
        end
    end

    Istiod -->|xDS API<br/>配置下发| EnvoyA
    Istiod -->|xDS API| EnvoyB
    Istiod -->|xDS API| EnvoyC

    EnvoyA <-->|mTLS| EnvoyB
    EnvoyA <-->|mTLS| EnvoyC
    EnvoyB <-->|mTLS| EnvoyC

    EnvoyA -->|遥测数据| Prometheus[Prometheus]
    EnvoyB -->|遥测数据| Prometheus
    EnvoyC -->|遥测数据| Prometheus

    EnvoyA -->|追踪数据| Jaeger[Jaeger]

Istiod 核心组件

Pilot:将高层路由规则转换为 Envoy 配置,通过 xDS API 下发给数据平面。

Citadel:管理证书的签发和轮转,实现服务间的 mTLS 通信。

Galley:验证 Istio 配置资源的正确性。

安装 Istio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 安装 istioctl
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH=$PWD/bin:$PATH

# 使用 demo profile 安装(含所有组件)
istioctl install --set profile=demo -y

# 生产环境推荐 default profile
istioctl install --set profile=default -y

# 为 namespace 启用自动 sidecar 注入
kubectl label namespace default istio-injection=enabled

# 验证安装
istioctl verify-install
kubectl get pods -n istio-system

流量管理

VirtualService

VirtualService 定义了流量如何路由到目标服务。它是 Istio 流量管理的核心资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 基于权重的流量分割 - 金丝雀发布
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: "test-user"
route:
- destination:
host: reviews
subset: v2
weight: 100
- route:
- destination:
host: reviews
subset: v1
weight: 90
- destination:
host: reviews
subset: v2
weight: 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 故障注入 - 测试弹性
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
delay:
percentage:
value: 10
fixedDelay: 5s
abort:
percentage:
value: 5
httpStatus: 500
route:
- destination:
host: ratings
subset: v1

DestinationRule

DestinationRule 定义了流量到达目标服务后的策略,包括负载均衡、连接池、熔断等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
h2UpgradePolicy: DEFAULT
http1MaxPendingRequests: 100
http2MaxRequests: 1000
maxRequestsPerConnection: 10
outlierDetection:
consecutive5xxErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
loadBalancer:
simple: ROUND_ROBIN
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: LEAST_REQUEST

流量管理场景

graph TB
    subgraph 金丝雀发布
        GW1[Gateway] -->|90%| V1A[v1]
        GW1 -->|10%| V2A[v2]
    end

    subgraph A/B 测试
        GW2[Gateway] -->|header: group=A| V1B[v1]
        GW2 -->|header: group=B| V2B[v2]
    end

    subgraph 蓝绿部署
        GW3[Gateway] -->|切换| V1C[v1 Blue]
        GW3 -.->|待切换| V2C[v2 Green]
    end

    subgraph 故障注入
        GW4[Gateway] -->|95% 正常| V1D[v1]
        GW4 -->|5% 注入延迟| V1D
    end

超时与重试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: order-service
spec:
hosts:
- order-service
http:
- route:
- destination:
host: order-service
timeout: 3s
retries:
attempts: 3
perTryTimeout: 1s
retryOn: "5xx,reset,connect-failure,retriable-4xx"
retryRemoteLocalities: true

安全:mTLS

双向 TLS 认证

Istio 自动为服务间通信提供 mTLS 加密,无需修改应用代码。

sequenceDiagram
    participant A as 服务 A (Envoy)
    participant Istiod
    participant B as 服务 B (Envoy)

    Note over Istiod: 证书颁发与管理

    Istiod->>A: 下发证书<br/>SPIFFE ID: spiffe://cluster/ns/default/sa/svc-a
    Istiod->>B: 下发证书<br/>SPIFFE ID: spiffe://cluster/ns/default/sa/svc-b

    A->>B: TLS 握手 (ClientHello)
    B-->>A: ServerHello + 服务端证书
    A->>B: 客户端证书
    Note over A,B: 双向验证身份

    A->>B: 加密的业务请求
    B-->>A: 加密的业务响应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# PeerAuthentication - 设置 mTLS 模式
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT # STRICT | PERMISSIVE | DISABLE

---
# AuthorizationPolicy - 服务级别的访问控制
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: order-service-policy
namespace: default
spec:
selector:
matchLabels:
app: order-service
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/api-gateway"
- "cluster.local/ns/default/sa/user-service"
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/orders/*"]
- from:
- source:
principals:
- "cluster.local/ns/default/sa/admin-service"
to:
- operation:
methods: ["GET", "DELETE"]
paths: ["/api/admin/orders/*"]

JWT 认证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# RequestAuthentication - JWT 验证
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: default
spec:
selector:
matchLabels:
app: api-gateway
jwtRules:
- issuer: "https://auth.example.com"
jwksUri: "https://auth.example.com/.well-known/jwks.json"
forwardOriginalToken: true
outputPayloadToHeader: "x-jwt-payload"

可观测性

Istio 的 Sidecar 代理自动采集所有服务间通信的遥测数据,无需应用代码集成。

指标(Metrics)

1
2
3
4
5
6
7
8
9
10
11
# Prometheus 自动采集 Envoy 指标
# 常用指标:
# istio_requests_total - 请求总数
# istio_request_duration_milliseconds - 请求延迟
# istio_tcp_connections_opened_total - TCP 连接数

# Grafana Dashboard 查询示例
# 服务请求成功率
# sum(rate(istio_requests_total{response_code!~"5.*"}[5m]))
# /
# sum(rate(istio_requests_total[5m]))

分布式追踪

graph LR
    subgraph 请求链路追踪
        A[API Gateway<br/>span-1] --> B[订单服务<br/>span-2]
        B --> C[支付服务<br/>span-3]
        B --> D[库存服务<br/>span-4]
        C --> E[风控服务<br/>span-5]
    end

    A -->|trace-id| Jaeger[Jaeger]
    B -->|trace-id| Jaeger
    C -->|trace-id| Jaeger
    D -->|trace-id| Jaeger
    E -->|trace-id| Jaeger

应用需要传播 trace header 才能实现完整的链路追踪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 在应用中传播 trace headers
@Component
public class TracingFilter implements Filter {
private static final List<String> TRACE_HEADERS = List.of(
"x-request-id",
"x-b3-traceid",
"x-b3-spanid",
"x-b3-parentspanid",
"x-b3-sampled",
"x-b3-flags",
"b3",
"traceparent",
"tracestate"
);

@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) request;

// 将 trace headers 存储到 ThreadLocal,供下游调用时使用
Map<String, String> traceContext = new HashMap<>();
for (String header : TRACE_HEADERS) {
String value = httpReq.getHeader(header);
if (value != null) {
traceContext.put(header, value);
}
}
TraceContextHolder.set(traceContext);

try {
chain.doFilter(request, response);
} finally {
TraceContextHolder.clear();
}
}
}

可观测性配套安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装 Prometheus, Grafana, Jaeger, Kiali
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/prometheus.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/grafana.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/jaeger.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/kiali.yaml

# 打开 Kiali 服务拓扑图
istioctl dashboard kiali

# 打开 Grafana 仪表盘
istioctl dashboard grafana

# 打开 Jaeger 追踪界面
istioctl dashboard jaeger

生产环境最佳实践

资源配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 为 Sidecar 设置资源限制
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
defaultConfig:
concurrency: 2 # Envoy worker 线程数
values:
global:
proxy:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi

性能优化建议

  1. 合理设置并发度:Envoy 的 worker 线程数应匹配 CPU 核数
  2. 连接池调优:根据实际 QPS 调整 connectionPool 配置
  3. 限制 Sidecar 作用域:使用 Sidecar 资源限制每个服务可见的上游服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Sidecar 作用域限制 - 减少 Envoy 配置大小
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: order-service
namespace: default
spec:
workloadSelector:
labels:
app: order-service
egress:
- hosts:
- "./payment-service.default.svc.cluster.local"
- "./inventory-service.default.svc.cluster.local"
- "istio-system/*"

渐进式采用策略

graph LR
    P1[阶段1<br/>PERMISSIVE mTLS<br/>可观测性] --> P2[阶段2<br/>流量管理<br/>灰度发布]
    P2 --> P3[阶段3<br/>STRICT mTLS<br/>授权策略]
    P3 --> P4[阶段4<br/>全面安全<br/>故障注入测试]

总结

Service Mesh 将服务间通信的复杂性从应用层下沉到基础设施层,让开发者专注于业务逻辑。Istio 作为最成熟的 Service Mesh 实现,提供了完善的流量管理、安全通信和可观测性能力。但它也带来了额外的资源开销和运维复杂度。建议采用渐进式策略,先从可观测性入手,逐步启用流量管理和安全策略。在中小规模系统中,也可以考虑 Linkerd 等更轻量的替代方案。

作者 · authorzt
发布 · date2025-05-23
篇幅 · length2.6k 字 · 7 min
许可 · licenseCC BY-SA 4.0
$ echo "comments" · 评论