Istio流量管理相关概念


重大发现:Istio官网的最下能选择中文,大家可以去官网浏览已经被翻译的中文文档,下面这篇是我不知道的情况下自行翻译的。

本文翻译自官方文档https://istio.io/latest/docs/concepts/traffic-management/,另外可以阅读红帽的文章概括地了解服务网格https://www.redhat.com/zh/topics/microservices/what-is-a-service-mesh

前言

Istio流量规则使你更加容易地控制服务间的流量和API调用。Istio简化服务级别特性的配置,例如熔断、超时和重试,也能够让配置一些重要的任务变得更加容易,例如AB测试、金丝雀部署和基于流量占比的分阶段部署。它还提供了开箱即用的故障恢复特性,帮助你的应用程序抵御来自服务和网络的故障。

Istio流量管理依赖与你的服务一起部署的Envoy代理。网格服务所有的发送和接收流量(数据平面流量)通过Envoy代理,使它能够容易地定向和控制与你网格相关的流量,避免对你的服务进行任何修改。

如果你对本指南中描述的特性的细节感兴趣,可以参考架构概述,本指南其他部分介绍了Istio流量管理方面的特性。

Istio流量管理介绍

为了定向网格中的流量,Istio需要知道所有的Endpoint位于何处以及它们所属的Service,为构建其自身的服务注册表,它将连接到服务发现系统,例如将Istio安装到K8s集群时,它会自动检测集群中的Service和Endpoint。

Envoy代理使用这个服务注册表定向流量到合适的服务。大部分微服务架构的应用程序每个服务使用多个实例处理流量,这有时被称为负载均衡池。默认情况下Envoy代理使用round-robin模式将流量分布到每个服务的负载均衡池,请求被轮询发送到每个池成员。

Istio基于服务发现和负载均衡为你提供了一个工作的服务网格,但这远不能达到Istio所拥有的能力。大多数情况下,你可能想要对网格流量进行更加精确的控制。你可能想定向特定比例的流量到一个新版服务,作为AB测试中的一部分,或者为服务的子集(Subsets)应用不同的负载均衡策略。你可能想为进出网格的流量应用指定的规则,或者为你的网格添加一个外部依赖到服务注册表中。你可以通过Istio的流量管理API添加配置,以完成这一切和更多。

就像其他的Istio配置,API使用K8s的自定义资源(CRD)指定,你可以使用YAML文件进行配置,像示例中一样。

本指南的剩余部分详细说明流量管理API的每个资源,以及你能使用他们做到什么。这些资源是:

  • 虚拟服务(Virtual services)
  • 目标规则(Destination rules)
  • 网关(Gateways)
  • 服务入口(Service entries)
  • 边车(Sidecars)

本指南还提供一些内建在API资源中的关于网络弹性和测试特性的介绍。

虚拟服务

虚拟服务和目标规则是Istio流量管理功能的要素,虚拟服务用于配置如何将请求路由到网格内的服务,它构建在平台和Istio提供的基本网络通信和服务发现基础上。虚拟服务包含一组按序匹配的路由规则,使Istio将指定的请求路由到网格内特定的目标上去,网格可以存在零个或者多个虚拟服务,这取决于你的用例。

为什么使用虚拟服务

虚拟服务在Istio构建强大和灵活的流量管理功能方面起到关键作用,它通过解耦客户端发送请求的目标位置与实现请求的实际负载来实现这一点。虚拟服务还提供丰富的方法为发送到工作负载的流量应用指定的路由规则。

这一点为何非常关键?不存在虚拟服务时,Envoy使用轮询的方式在负载之间分发请求,像前言中说的一样。你可以通过对负载的了解改变这一行为。例如一些实例可能使用不同的版本。这在AB测试中很有用,你可能想基于不同的版本配置流量比例,或者将来自内部用户的流量定向到一组特定的实例。

使用虚拟服务,你可以为一个或多个主机名指定流量行为,使用虚拟服务中的路由规则去告诉Envoy如何将虚拟服务的流量转发到合适的目的地。路由目的地可以是同服务的不同版本或者是完全不同的服务。

一个典型的用例是发送流量到同服务的不同版本,通过服务的子集指定。客户端发送请求到虚拟服务就像发送到一个单一实体,此时Envoy根据虚拟服务的路由规则将流量转发至不同的版本:例如“20%调用到新版本”或者“来自这个用户的调用到版本2”。这将使你能够创建一个金丝雀部署,将流量按照百分比逐步迁移到新版本。流量路由与实例部署完全分离,意味着基于流量负载的新服务版本实例数量的上下扩展不需要考虑流量路由相关的一切。相比较,像K8s这样的容器编排平台只能提供基于实例比例的流量分布,这会很快让事情变得复杂起来,你可以阅读使用Istio进行金丝雀部署了解更多关于虚拟服务如何帮助进行金丝雀部署

虚拟服务也能使你:

  • 通过单个虚拟服务解决多应用服务问题。如果你的网格使用K8s,例如你可以配置一个虚拟服务处理指定命名空间(Namespace)内的所有服务(Service)。将一个虚拟服务映射到多个真实服务有助于单体应用向由服务集合构成的微服务架构的转变,因为可以避免服务消费者为适应这个改变做出更改。你的路由规则可以指定“对于URI monolith.com的调用指向服务A”类似的行为。你可以在一个例子中看到这是如何工作的。
  • 流量规则与网关结合,可以控制进(Ingress)出(Egress)流量。

在一些情况下,你也需要配置目标规则用来使用这些特性,因为这是指定你服务子集的地方。在独立的对象中定义服务子集和其他特定用途的规则可以让你在虚拟服务之间重用这些配置。在后面的章节中可以找到更多关于目标规则的内容。

虚拟服务示例

以下示例基于用户将请求路由到不同的服务版本:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v3

hosts字段

hosts字段列出了虚拟服务的主机,换句话说就是用户可寻址的目标或者可以应用路由规则的目标。这是客户端用来向服务发送请求的地址。

hosts:
- reviews

虚拟服务的主机名可以是IP地址、DNS名字,或者取决于依赖的平台,例如K8s中可解析的服务短名称,隐式或显式地到一个完全限定域名(FQDN)。你也可以使用前缀通配符(“*”),为所有服务创建一组路由规则。虚拟服务的主机不一定是Istio服务注册表的一部分,它仅仅是一个虚拟的目的地。这使你可以为网格内没有可路由入口的虚拟主机的流量建模。

路由规则

虚拟服务的路由规则包含在http部分,它描述了将HTTP/1.1、HTTP2和gRPC流量路由到hosts字段中指定的目的地所需要匹配的条件和行为(你也可以使用tcp和tls部分为TCP和未终结的TLS流量配置路由规则)。一个路由规则由你想到达的目的地和零个或多个条件组成,这取决于你的用例。

匹配条件

示例中的第一个路由规则从包含匹配条件的match字段开始。示例场景中你想将路由规则应用于来自用户jason的请求,所以你使用headers、end-user和exact字段选择合适的请求。

- match:
   - headers:
       end-user:
         exact: jason
目的地

route部分的destination字段指定匹配条件的流量的真实目的地。不同于虚拟服务的hosts,目的地的host必须是一个存在于Istio服务注册表中的真实目的地,否则Envoy不知道将流量发向何处。这可以是一个具备代理的网格服务或者一个通过服务入口添加的非网格服务。示例运行在K8s中,host是K8s中的服务名称。

route:
- destination:
    host: reviews
subset: v2

需要注意,为简单起见本例和指南中的其他示例使用K8s的短名称作为目的地的hosts。提交和应用规则时,Istio基于虚拟服务所在的命名空间为短名称添加域名后缀,为host获取完全限定名称。示例中使用短名称也意味着你可以在任何命名空间中进行实验。

只有当目的地hosts与虚拟服务位于相同的K8s命名空间时短名称才能工作。由于使用K8s短名称能够导致配置错误,我们建议你在生产环境中指定完全限定主机名。

destination部分也可以指定将符合条件的请求路由至K8s服务的子集,在示例中,子集的名称为v2。你将在后面的目标规则部分看到如何定义服务子集。

路由规则优先级

路由规则按照从上到下的顺序进行评估,虚拟服务中定义的第一条路由规则拥有最高的优先级。在示例中通过第二个规则指定默认目的地,将任何没有匹配第一个规则的请求路由到默认目的地。因此,第二个规则不包含规则,直接将流量定向到v3子集。

- route:
  - destination:
      host: reviews
      subset: v3

我们建议提供一个无条件或者基于权重的规则(见下面的描述)作为每个虚拟服务的最后一个规则,确保到达虚拟服务的流量至少匹配一个路由。

关于路由规则的更多内容

如前所述,路由规则是一个路由指定子集流量到指定目的地的强大工具。你可以设置基于流量端口、Header字段、URI等的匹配条件。例如,示例中的虚拟服务将用户发送的流量路由到两个独立的服务ratings和reviews,就像他们是一个更大的虚拟服务http://bookinfo.com/ 的一部分。虚拟服务规则基于请求URI将匹配的流量指向特定的服务。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    - destination:
        host: reviews
  - match:
    - uri:
        prefix: /ratings
    route:
    - destination:
        host: ratings

对于一些匹配条件,也可以选择精确值、前缀或者正则。

你可以在相同的match块中添加多个规则,以AND逻辑进行匹配,也可以在同一个规则中添加多个match块,以OR的逻辑进行匹配。你也可以为任何给定的虚拟服务设置多个路由规则。这使你可以根据需要在一个虚拟服务中配置复杂或简单的路由条件。匹配条件和其可能值的完整列表参考匹配HTTP请求

使用匹配条件之外,你可以通过weight字段设置的百分比进行流量分布。这在AB测试和金丝雀部署中非常有用:

spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 75
    - destination:
        host: reviews
        subset: v2
      weight: 25

你还可以使用路由规则对流量执行一些操作,例如:

  • 添加或者移除headers。
  • 重写URL。
  • 为目的地的调用设置重试策略。

学习关于可用操作的更多内容,参考HTTP路由

目标规则

与虚拟服务一样,目标规则也是Istio实现流量路由功能的关键部分。你可以把虚拟服务视为如何将流量路由至给定的目的地,然后使用目标规则配置流量到达目的地后会发生什么。目标规则在虚拟服务的路由规则评估后应用,所以它应用于流量的真实目的地。

特别的是,你可以使用目标规则指定命名服务的子集,例如使用版本对给定服务的所有实例进行分组。然后你可以在虚拟服务的路由规则中使用这些服务子集以控制流量到不同的服务实例。

入口规则也使你能够在调用目标服务或者服务的子集时定制Envoy的流量规则,例如选择负载均衡模式、TLS安全模式或者熔断设置。查看目标规则参考以了解目标规则配置项的完整列表。

负载均衡选项

Istio默认使用round-robin负载均衡策略,实例池中的服务实例以轮询的方式获取请求。Istio也能够支持以下模式,你可以在目标规则中指定对特定服务或服务子集的请求。

  • 随机模式:请求随机转发到实例池中的实例。
  • 权重模式:依据配置的权重将请求转发到实例池中的实例。
  • 最少请求模式:请求转发到接收请求最少的实例。

查看Envoy负载均衡文档了解更多。

目标规则示例

以下目标规则示例为服务my-svc配置了三个不同的子集,使用不同的负载均衡策略:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: my-destination-rule
spec:
  host: my-svc
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
  - name: v3
    labels:
      version: v3

每个子集基于一个或多个标签(Labels)定义,在K8s中是附加在类似Pod这样的对象上的键值对。这些标签应用于K8s服务部署中的metadata中,用以标识不同的版本。

除定义服务子集外,这个目标规则还包含两个流量策略,一个是对所有子集的默认策略,一个是在子集中重写的针对该子集的策略。默认策略定义在subsets字段之外,示例为v1、v3子集设置了RANDOM类型的负载均衡策略。在v1子集中,ROUND_ROBIN策略在相应的子集字段中指定。

网关

网关用于管理网格的进出流量,能够让你指定哪些流量可以进入或者离开网格。网关配置应用于网格边缘运行的独立Envoy代理,而不是与你的服务一起运行的边车Envoy代理。

与其他控制流量进入你的系统的方式不同,比如K8s Ingress API,Istio网关让你使用Istio流量路由的全部能力和灵活性。使用Istio网关资源能够在4-6层网络配置负载均衡特性,例如暴露端口、TLS设置等。而不用添加应用层(L7)流量路由到相同的API资源只需要将常规的Istio虚拟服务绑定到网关。这基本上能够让你像管理网格中的数据平面流量一样管理网关流量。

网关主要用于管理入流量,但是你也可以配置出流量网关。出流量网关使你为离开网格的流量配置专用的出节点,让你能够限制哪些服务能够或者应该访问外部网络,或者启用出流量安全控制以增加网格的安全性。你还可以使用网关配置一个纯内部代理。

Istio提供一些预制的网关代理部署(istio-ingressgateway和istio-egressgateway),当使用我们的demo配置安装时,两者都会被部署,而在默认配置安装中,只有入流量网关会被安装。你可以应用自己的网关配置到这些部署,或者部署和配置自己的网关代理。

网关示例

以下示例展示了一个可能的针对外部HTTPS入流量的网关配置:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: ext-host-gwy
spec:
  selector:
    app: my-gateway-controller
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - ext-host.example.com
    tls:
      mode: SIMPLE
      credentialName: ext-host-cert

这个网关配置使HTTPS流量从ext-host.example.com的443端口进入网格,但是没有为流量指定路由。

要指定路由并使网关按照预期工作,你必须绑定网关到虚拟服务。你可以像以下示例中一样在虚拟服务的gateways字段绑定网关:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: virtual-svc
spec:
  hosts:
  - ext-host.example.com
  gateways:
  - ext-host-gwy

然后,你可以在虚拟服务中为外部流量配置路由规则。

服务入口

你可以使用服务入口为Istio内部维护的服务注册表添加服务入口。添加服务入口后,Envoy代理向服务发送流量就像这个服务在网格内一样。配置服务入口能够允许你管理运行在网格外部的服务的流量,包括以下任务:

  • 为外部目标重定向和转发流量,例如使用来自WEB的API,或者基于传统基础设施服务的流量。
  • 为外部服务定义重试、超时和故障注入规则。
  • 网格中添加虚拟机,并在虚拟机中运行网格服务。

你不必为每个网格服务使用的外部服务添加服务入口。默认情况下Istio允许Envoy代理放行通向未知服务的请求。但是,你无法使用Istio的特性去管理没有在网格内注册的目的地的流量。

服务入口示例

以下示例中将外部服务入口依赖ext-svc.example.com添加到Istio的服务注册表:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: svc-entry
spec:
  hosts:
  - ext-svc.example.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  location: MESH_EXTERNAL
  resolution: DNS

使用hosts字段指定外部资源。可以使用全限定或者通配符前缀的域名。

你可以像对网格内的任何服务一样,配置虚拟服务和目标规则以更细的粒度控制到服务入口的流量。例如,以下目标规则将流量路由配置为使用双向TLS,去保护到以服务入口方式添加的外部服务ext-svc.example.com的连接:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: ext-res-dr
spec:
  host: ext-svc.example.com
  trafficPolicy:
    tls:
      mode: MUTUAL
      clientCertificate: /etc/certs/myclientcert.pem
      privateKey: /etc/certs/client_private_key.pem
      caCertificates: /etc/certs/rootcacerts.pem

查看服务入口参考了解更多配置项。

边车

默认情况下,Istio配置Envoy代理接收其关联工作负载所有端口的流量,转发流量将到达网格内的每个工作负载。你可以使用边车配置以下内容:

  • 微调Envoy代理接收的端口和协议。
  • 限制Envoy代理可以到达的服务。

你可能想在大型的应用中限制边车的可达性,在将每个代理配置为可访问网格中所有服务时,导致的高内存占用潜在影响网格的性能。

你可以指定你希望的边车配置到指定命名空间的所有工作负载,或者使用workloadSelector选择指定的工作负载。例如,以下边车配置使得bookinfo命名空间内的服务只能访问相同命名空间内的服务和Istio控制平面(当前需要使用Istio的策略和遥测特性):

apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
  name: default
  namespace: bookinfo
spec:
  egress:
  - hosts:
    - "./*"
    - "istio-system/*"

查看边车参考了解更多细节。

网络弹性和测试

除了帮助你定向网格周围的流量外,Istio提供了可在运行时动态配置的可选的故障恢复和故障注入特性。使用这些特性可帮助你的应用可靠运行,确保服务网格能够容忍节点故障并且阻止故障从本地向全局扩散。

超时

超时是Envoy代理应该等待给定服务响应的时间,确保服务不会无限期的等待响应和能够在预期的时间内返回成功或者失败。Istio默认禁止Envoy的HTTP请求超时。

对于一些应用和服务,Istio默认的超时配置可能是不合适的。例如过长的超时时间可能导致太多的时间用于等待故障服务的响应,而过短的超时时间可能导致在一个调用涉及多个服务的返回时发生不必要的失败。Istio使你在不考虑修改服务代码的情况下,基于每个服务的虚拟服务非常容易地实现超时时间动态调整,从而帮助你找到并应用最佳的超时时间。示例中的虚拟服务为ratings服务的v1子集调用指定了10秒超时时间:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
    timeout: 10s

重试

重试指定了在初始调用失败时Envoy代理尝试连接到服务的最大次数。重试能够提高服务的可用性和应用的性能,通过确保在发生类似服务或网络过载这样的暂时性故障时调用不会永久失败来实现。重试间隔(25ms+)是可变的,并且由Istio自动决定,以防止大量请求淹没被调用的服务。HTTP请求的默认重试行为是在返回错误之前重试两次。

与超时一样,Istio的默认重试行为可能不适合你的应用在延迟(对故障服务进行太多的重试导致延迟上升)和可用性方面的需求,同样类似于超时,你可以基于每个服务的虚拟服务设置重试次数,而不用考虑服务代码。你也可以通过添加每次重试的超时时间优化重试行为,这代表每次重试时,你想等待的尝试成功连接到服务的时长。下面的示例配置了连接到服务子集的最大重试次数是3,初次调用失败后,每个调用有2秒超时时间:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
    retries:
      attempts: 3
      perTryTimeout: 2s

熔断

熔断是Istio提供的另一个用于构建弹性微服务应用的机制。在断路器中,为服务中单个主机的调用设置了限制,例如并发连接数和调用失败计数。一旦到达限制值,断路器将切断到该服务的连接。使用断路器可以实现快速失败,从而避免客户端尝试连接到一个过载或者故障的主机。

断路器适用于负载均衡池中的真实网格目的地,因此它的阈值配置在目标规则中,并应用于服务中每个单独的主机。下面的示例将reviews服务v1子集的并发连接限制为100:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
    trafficPolicy:
      connectionPool:
        tcp:
          maxConnections: 100

查看断路器了解创建断路器的细节。

故障注入

配置好网络策略,包括故障恢复策略后,你可以使用故障注入机制测试整个应用的故障恢复能力。故障注入是一种将错误引入系统的方法,以确保它能够承受错误并从错误中恢复。使用故障注入能够验证故障恢复策略的可用性,防止恢复策略因为不兼容或者其他方面的限制导致关键服务故障。

与其他注入错误的机制不同,例如在网络层延迟数据包或者杀死Pod,Istio在让你在应用层注入故障。这让你能够注入更多符合意图的失败,例如HTTP错误码,用来获取更多相关的结果。

你可以使用虚拟服务注入两种类型的故障:

  • 延迟,计时失败,用于模拟网络延迟上升或者上游服务过载。
  • 中止,崩溃失败,用于模拟上游服务故障,通常以HTTP错误码和TCP连接失败出现。

下面的示例为ratings服务注入了每1000个请求出现一个5秒超时的故障:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - fault:
      delay:
        percentage:
          value: 0.1
        fixedDelay: 5s
    route:
    - destination:
        host: ratings
        subset: v1

阅读故障注入了解更多。

使用你的应用程序

Istio的故障恢复特性对应用完全透明。在返回响应之前,应用并不知道Envoy边车代理是否正在处理被调用服务的故障。这意味着如果你继续在应用代码中执行故障恢复策略时,你应该知道它们两者是独立工作的,因此存在发生冲突的可能。例如存在两个超时,分别在应用程序和虚拟服务中配置。在应用程序中为服务的API调用设置了2秒超时,同时在虚拟服务中配置了3秒超时和1次重试,此时应用程序中的超时首先生效,Envoy中的超时和重试将不会生效。

虽然Istio故障恢复特性提高了网格服务的可靠性和可用性,但是应用程序必须处理失败和错误,并采取适当的回退措施。例如,负载均衡池中的所有实例发生故障时,Envoy返回HTTP 503错误。应用程序必须实现处理503错误需要的任何回退逻辑。

posted @ 2021-07-13 23:33  AEROJET  阅读(166)  评论(0)    收藏  举报