实验2:流量分割

在这个实验中,我们将学习如何使用运行时分数和加权集群来配置 Envoy 的流量分割。

使用运行时分数

当我们只有两个上游集群时,运行时分数是一种很好的流量分割方法。运行时分数的工作原理是提供一个运行时分数(例如分子和分母),代表我们想要路由到一个特定集群的流量的分数。然后,我们使用相同的条件(即,在我们的例子中相同的前缀)提供第二个匹配,但不同的上游集群。

让我们创建一个 Envoy 配置,对 70% 的流量返回状态为 201 的直接响应。其余的流量返回状态为 202。

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: hello_service
          http_filters:
          - name: envoy.filters.http.router
          route_config:
            virtual_hosts:
            - name: hello_vhost
              domains: ["*"]
              routes:
                - match:
                    prefix: "/"
                    runtime_fraction:
                      default_value:
                        numerator: 70
                        denominator: HUNDRED
                      runtime_key: routing.hello_io
                  direct_response:
                    status: 201
                    body:
                      inline_string: "v1"
                - match:
                    prefix: "/"
                  direct_response:
                    status: 202
                    body:
                      inline_string: "v2"

将上述 Envoy 配置保存为 2-lab-2-traffic-splitting-1.yaml,并以该配置运行 Envoy。

func-e run -c 2-lab-2-traffic-splitting-1.yaml

在 Envoy 运行时,我们可以使用 hey 工具向代理发送 200 个请求。

$ hey http://localhost:10000
...
Status code distribution:
  [201] 142 responses
  [202] 58 responses

看一下状态代码的分布,我们会注意到,我们收到 HTTP 201 响应大概占 71%,其余的响应是 HTTP 202 响应。

使用加权集群

当我们有两个以上的上游集群,我们想把流量分给它们,我们可以使用加权集群的方法。在这里,我们单独给每个上游集群分配权重。我们在以前的方法中使用了多个匹配,而在加权集群中,我们将使用一个路由和多个加权集群。

对于这种方法,我们必须定义实际的上游集群。我们将运行 httpbin 镜像的三个实例。让我们在 3030、4040 和 5050 端口上运行三个不同的实例;我们将在 Envoy 配置中把它们称为 instance_1instance_2instance_3

docker run -d -p 3030:80 kennethreitz/httpbin
docker run -d -p 4040:80 kennethreitz/httpbin
docker run -d -p 5050:80 kennethreitz/httpbin

一个上游集群可以通过以下片段来定义。

  clusters:
  - name: instance_1
    connect_timeout: 5s
    load_assignment:
      cluster_name: instance_1
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 3030

让我们创建 Envoy 配置,将 50% 的流量分给 instance_1,30% 分给 instance_2,20% 分给 instance_3

我们还将启用管理接口来检索指标,这些指标将显示向不同集群发出的请求数量。

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: listener_http
          http_filters:
          - name: envoy.filters.http.router
          route_config:
            name: route
            virtual_hosts:
            - name: vh
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  weighted_clusters:
                    clusters:
                      - name: instance_1
                        weight: 50
                      - name: instance_2
                        weight: 30
                      - name: instance_3
                        weight: 20
  clusters:
  - name: instance_1
    connect_timeout: 5s
    load_assignment:
      cluster_name: instance_1
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 3030
  - name: instance_2
    connect_timeout: 5s
    load_assignment:
      cluster_name: instance_1
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 4040
  - name: instance_3
    connect_timeout: 5s
    load_assignment:
      cluster_name: instance_1
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 5050
admin:
  address:
    socket_address:
      address: 127.0.0.1
      port_value: 9901

将上述 YAML 保存为 2-lab-2-traffic-splitting-2.yaml 并运行代理程序:func-e run -c 2-lab-2-traffic-splitting-2.yaml

一旦代理运行,我们将使用 hey 来发送 200 个请求。

hey http://localhost:10000

来自 hey 的响应不会帮助我们确定分割,因为每个上游集群的响应都是 HTTP 200。

要想看到流量的分割,请在 http://localhost:9901/stats/prometheus 上打开统计表。在指标列表中,寻找 envoy_cluster_external_upstream_rq 指标,该指标计算外部上游请求的数量。我们应该看到与此类似的分割。

# TYPE envoy_cluster_external_upstream_rq counter
envoy_cluster_external_upstream_rq{envoy_response_code="200",envoy_cluster_name="instance_1"} 99
envoy_cluster_external_upstream_rq{envoy_response_code="200",envoy_cluster_name="instance_2"} 63
envoy_cluster_external_upstream_rq{envoy_response_code="200",envoy_cluster_name="instance_3"} 38

如果我们计算一下百分比,我们会发现它们与我们在配置中设置的百分比相对应。