前提条件:

  • 部署服务(deployment、service)并注入sidecar

我这里还是使用官方提供的bookinfo程序,选择productpage作为熔断目标

kubectl apply -f - << EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: productpage
spec:
  host: productpage
  subsets:
  - name: v1
    labels:
      version: v1
EOF

在之前的文档中,设置了目标路由的subset,使virtual service能够识别版本,本文中流量熔断是基于目标路由配置的设置。

测试工具

这是一个名为 Fortio 的负载测试客户端, 它可以控制连接数、并发数及发送 HTTP 请求的延迟。 通过 Fortio 能够有效的触发前面在 DestinationRule 中设置的熔断策略

注意:Fortio也需要注入sidecar

kubectl apply -f - << EOF
apiVersion: v1
kind: Service
metadata:
  name: fortio
  labels:
    app: fortio
    service: fortio
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: fortio
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fortio-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fortio
  template:
    metadata:
      annotations:
        # This annotation causes Envoy to serve cluster.outbound statistics via 15000/stats
        # in addition to the stats normally served by Istio. The Circuit Breaking example task
        # gives an example of inspecting Envoy stats via proxy config.
        proxy.istio.io/config: |-
          proxyStatsMatcher:
            inclusionPrefixes:
            - "cluster.outbound"
            - "cluster_manager"
            - "listener_manager"
            - "server"
            - "cluster.xds-grpc"
      labels:
        app: fortio
    spec:
      containers:
      - name: fortio
        image: fortio/fortio:latest_release
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          name: http-fortio
        - containerPort: 8079
          name: grpc-ping
EOF

测试并发数

  1. 获取Fortio pod名称

    export FORTIO_POD=$(kubectl get pods -l app=fortio -o 'jsonpath={.items[0].metadata.name}')
  2. 测试并发

    kubectl exec "$FORTIO_POD" -c fortio -- /usr/bin/fortio load -c 10 -qps 0 -n 1 -loglevel Warning http://productpage:9080/productpage

    -c : 每次连接的并发连接数

    -n : 发送连接次数

配置Destination Rule

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: productpage
spec:
  host: productpage
  subsets:
  - name: v1
    labels:
      version: v1
  # 以下是新增的流量策略
  trafficPolicy:
    # 设置连接池
    connectionPool:
      tcp:
        # tcp最大链接数为1
        maxConnections: 1
      http:
        # http最大等待请求数为1
        http1MaxPendingRequests: 1
        # 每个连接的最大请求数为1
        maxRequestsPerConnection: 1
    # 异常检测,用于自动检测并排除异常的服务实例
    outlierDetection:
      # 连续的 5xx 错误计数,当达到这个阈值时,实例会被标记为异常
      consecutive5xxErrors: 1
      # 检测的时间窗口,这里是每秒检测一次
      interval: 1s
      # 基础排除时间,当实例被标记为异常后,它会在这段时间内被排除,这里是 3 分钟
      baseEjectionTime: 3m
      # 允许被排除的最大实例百分比,这里是 100%,意味着所有实例都可能被排除
      maxEjectionPercent: 100
EOF

再次测试

  1. 获取Fortio pod名称

    export FORTIO_POD=$(kubectl get pods -l app=fortio -o 'jsonpath={.items[0].metadata.name}')
  2. 测试并发

    kubectl exec "$FORTIO_POD" -c fortio -- /usr/bin/fortio load -c 10 -qps 0 -n 1 -loglevel Warning http://productpage:9080/productpage

istio-proxy 允许存在一些误差,所以偶尔会出现拦截9个请求偶尔拦截8个请求,这与各种因素有关,只需要关心大概范围即可。

查看详细熔断日志

多次并发测试后可以通过日志了解更多熔断详情

kubectl exec "$FORTIO_POD" -c istio-proxy -- pilot-agent request GET stats | grep productpage | grep pending

其中110个被请求标记为熔断,20个请求通过