流量管理
使用 Istio 的流量管理模型,本质上是将流量与基础设施扩容解耦,让运维人员可以通过Pilot指定流量遵循什么规则,而不是指定哪些 pod/VM 应该接收流量。例如,你可以将10%的流量转发到测试版本服务,或根据请求的内容将流量发送到特定版本。如下图所示:
将流量从基础设施扩展中解耦,这样就可以让 Istio 提供各种独立于应用程序代码之外的流量管理功能。除了A/B测试的动态路由外,它还具有超时、重试和熔断等功能来处理故障,最后还可以通过故障注入来测试服务之间故障恢复策略的兼容性。这些功能都是通过部署的Envoy/sidecar代理来实现的。
Pilot和Envoy
Istio流量管理核心组件是Pilot,它管理和配置部署在Istio服务中的所有Envory代理,它允许您指定在 Envoy 代理之间使用什么样的路由流量规则,并配置故障恢复功能,如超时、重试和熔断等。它还维护了所有Istio服务的规范模型,并使用这个模型通过发现服务让 Envoy 了解网格中的其他实例。
每个 Envoy 实例都会维护负载均衡信息信息,这些信息来自 Pilot 以及对负载均衡池中其他实例的定期健康检查。从而允许其在目标实例之间智能分配流量,同时遵循其指定的路由规则。
Pilot 负责管理通过Istio服务中的Envoy实例的生命周期。Pilot架构图如下:
如上图所示,Pilot维护了一个服务规则表并独立于底层平台。Pilot中的特定于平台的适配器负责适当地填充这个规范模型。如:在Pilot中的Kubernetes 适配器实现了必要的控制器,来观察kubernetes API 服务器,用于更改 pod 的注册信息、入口资源以及存储流量管理规则的第三方资源。这些数据被转换为规范表示。然后根据规范表示生成特定的 Envoy 的配置。
Pilot 公开了用于服务发现 、负载均衡池和路由表的动态更新的 API。
运维人员可以通过 Pilot 的 Rules API 指定高级流量管理规则。这些规则被翻译成低级配置,并通过 discovery API 分发到 Envoy 实例。
请求路由
根据之前内容可知,Pilot维护Istio服务规范表。服务的 Istio 模型和在底层平台(Kubernetes、Mesos 以及 Cloud Foundry 等)中的表达无关。特定平台的适配器负责从各自平台中获取元数据的各种字段,然后对服务模型进行填充。
Istio引入了服务版本的概念,可以通过版本(v1
、v2
)或环境(staging
、prod
)对服务进行进一步的细分。这些版本不一定是不同的 API 版本:它们可能是部署在不同环境(prod、staging 或者 dev 等)中的同一服务的不同迭代。例如:A/B测试或金丝雀部署。Istio 的流量路由规则可以根据服务版本来对服务之间流量进行附加控制。
服务间通讯
如上图所示,服务的客户端不知道服务不同版本间的差异。它们可以使用服务的主机名或者 IP 地址继续访问服务。Envoy sidecar/代理拦截并转发客户端和服务器之间的所有请求和响应。
运维人员使用Pilot指定路由规则,Envoy根据这些规则动态地确定实际的服务版本,如,Envoy可以根据规则中的header、标签或权重等标准进行版本选择。该模型使应用程序代码能够将它从其依赖服务的演进中解耦出来,同时还有诸多好处,下面具体讨论。
Istio 还为同一服务版本的多个实例提供流量负载均衡。Istio 不提供 DNS,应用程序可以使用底层平台的DNS服务,如kubernetes平台的CoreDNS等。
Ingress 和 Egress
Istio假定进站流量和出站流量都会通过Envoy代理进行传输。通过将Envoy代理部署在服务之前,运维人员可以通过用户的服务进行A/B测试、部署金丝雀服务等。比如,运维人员通过Pilot编写路由规则,由Envoy解析和应用该规则将流量路由到外部Web服务,当然,运维人员也可以为这些服务添加超时、熔断和重试等功能,同时也可以从服务连接中获取各种细节指标。流量流如下图所示:
服务发现和负载均衡
Istio假定存在服务注册表,来跟踪应用程序中服务的 pod/VM。它还假定新的服务将被注册到服务注册表中,并且不健康的实例被自动删除。如Kubernetes、Mesos 等平台已经为基于容器的应用程序提供了这样的功能。
Pilot使用服务注册信息,并提供与平台无关的服务发现接口。Istio中的Envoy实例执行服务发现,并相应地动态更新其负载均衡池。
如上图所示,网格中的服务使用其 DNS 名称访问彼此。服务所有的HTTP流量都会通过Envoy自动重新路由。Envoy在负载均衡池中的实例之间分发流量,虽然 Envoy 支持多种复杂的负载均衡算法,但 Istio 目前仅允许三种负载均衡模式:
- 轮询
- 随机
- 权重
除了负载均衡外,Envoy 还会定期检查池中每个实例的运行状况。Envoy 遵循熔断器风格模式,根据健康检查 API 调用的失败率将实例分为健康和不健康两种。换句话说,当给定实例的健康检查失败次数超过预定阈值时,将会被从负载均衡池中移除,同理,失败次数低于预定阈值时,该实例将被添加回负载均衡池。
服务可以通过使用 HTTP 503 响应健康检查来主动减轻负担。在这种情况下,服务实例将立即从调用者的负载均衡池中删除。
故障处理
Envoy提供了一套可选的故障恢复功能,主要包括:
1、超时处理
2、重试处理
3、请求数限制,即限流
4、对负载均衡器中每个成员主动(定期)运行健康检查
5、细粒度熔断器,被动的去检查服务
以上功能都可以使用Istio的流量管理规则在运行时动态配置,主动和被动健康检查(上述 4 和 5 )的组合最大限度地减少了在负载均衡池中访问不健康实例的机会。当将其与平台级健康检查(例如由 Kubernetes 或 Mesos 支持的检查)相结合时, 可以确保应用程序将不健康的 Pod/容器/虚拟机快速地从服务网格中去除,从而最小化请求失败和延迟产生影响。
总之,以上功能,都有利于故障排查和修复,提高服务运行的稳定性。
微调
Istio 的流量管理规则允许运维人员为每个服务/版本设置故障恢复的全局默认值。然而,服务的消费者也可以通过特殊的 HTTP 头提供的请求级别值覆盖超时和重试的默认值。在 Envoy 代理的实现中,对应的 Header 分别是x-envoy-upstream-rq-timeout-ms
和 x-envoy-max-retries
。
故障注入
虽然Envoy sidecar/proxy 为Istio上运行的服务提供了大量的故障恢复机制,但测试整个应用程序端到端的故障恢复能力依然是必须的。错误配置的故障恢复策略
,
可能导致应用程序中的关键服务持续不可用,从而破坏用户体验。
Istio 能在不杀死 Pod 的情况下,将特定协议的故障注入到网络中,应用层观察到的故障都是一样的,并且可以在应用层注入更有意义的故障,以检验和改善应用的弹性。
运维人员可以为符合特定条件的请求配置故障,还可以进一步限制遭受故障的请求的百分比。可以注入两种类型的故障:延迟和中断。延迟是计时故障,模拟网络延迟上升或上游服务超载的情况。中断是模拟上游服务的崩溃故障。中断通常以 HTTP 错误代码或 TCP 连接失败的形式表现。