服务级故障是云上云原生业务可能遭遇到的一类较为常见的故障类型,故障范围将小于可用区级别,但仍会因为服务单点故障造成业务不可用或降级问题。服务网格ASM支持打通多个集群的服务发现以及网络互访,结合多地域、多集群的服务对等部署模式,在任意的服务发生故障时,只要集群中还存在可用的服务工作负载实例,服务网格 ASM(Service Mesh)都可以秒级对流量目标实现无感切换,保证业务应用在全局的可用性。本文介绍如何使用服务网格应对服务级故障容灾。
容灾架构
故障转移机制:服务网格基于地理位置的故障转移
ASM支持基于地理位置的故障转移机制。通过持续检测一段时间窗口内,工作负载是否连续发生响应错误来判断工作负载的故障状态,并在工作负载故障时自动将流量目标转移到其他可用的工作负载上。
以下以分别位于两个不同地域的集群为例,在其中对等部署两套应用。每个集群的每个服务的工作负载通过拓扑分布约束(Topology Spread Constraints)均匀分布在不同可用区。
正常流量拓扑。
在服务均为正常的情况下,服务网格会将流量保持在同一可用区,以最小化调用目标位置对请求延迟的影响。
工作负载异常时,按照地理位置规划自动故障转移。
当ASM检测到工作负载连续出现响应错误的情况,会将该服务剔除出负载均衡池,以将请求目标转移到其它可用的工作负载上。流量故障转移会按照如下的优先级顺序进行:
其他同可用区的工作负载。
同地域不同可用区的工作负载。
同时,通过配置Prometheus实例采集服务网格相关指标,当故障转移发生时,可通过指标告警通知到相关业务联系人。
跨地域流量转移。
当同地域下的可用区都没有可用的工作负载时,还可以将流量转移到另一个地域下其他集群中对等部署的相同服务。此过程由服务网格自动完成。
在这种情况下,需要依赖两个集群之间的路由打通:即从A集群的Pod可以连通B集群的Pod。对于阿里云多地域的场景,此时可以选择使用CEN(云企业网)打通集群之间的物理网络、实现集群互通。此方案需要对集群网络(Pod、Service、VPC CIDR等)进行规划,并借助云企业网实例实现跨地域网络打通,适用于对跨地域流量具有高质量要求的客户。
而IDC/三方云厂商的集群,往往存在由于网络规划无法将物理网络打通的限制。针对这种情况,ASM提供了通过跨集群网络代理的方式,在集群间建立一条mTLS的安全信道,用于必要的跨集群通信和实现安全的跨地域流量转移。但基于质量有限的公网通信,该方案适用于对集群间通信具有非强需求、或因现实原因导致集群物理网络冲突的用户。
应用部署拓扑:多种集群拓扑的支持方式及对比
ASM基于地理位置的故障转移机制可以无缝应用在多种应用部署的拓扑方式之中,不同的部署拓扑会有故障维度的支持范围以及资源成本、运维门槛上的区别。可根据实际资源及应用状况选择。
单集群多可用区部署。
此方式为容灾中最简单的部署方式。通过配置多可用区(AZ)节点池,为节点池选择多AZ的虚拟交换机,并在配置扩缩容策略时选择均衡分布策略,即可在伸缩组指定的多可用区之间均匀分配ECS实例。
此方式的优缺点对比:
优点
缺点
优点
缺点
只需要开通一个包含多可用区节点池的ACK集群、并通过拓扑分布约束(Topology Spread Constraints)在可用区间均匀部署应用。
无法处理由于Kubernetes错误配置、应用程序依赖等造成的故障。
负载均衡、数据库、Kubernetes集群、服务网格等云资源只需要在同一地域内准备一份。
无法处理地域级别的故障。
单地域多可用区多集群部署。
在单集群多可用区基础上,将单集群扩展为多集群,每个集群各自拥有一套配置。当故障转移发生时,ASM会优先寻找同可用区的其他工作负载、接着会在同地域不同可用区的其他可用工作负载中任选一个作为故障转移目标。同时,建议为两个集群分别选择各自独立的可用区。如果两个集群的可用区重合,可能会造成同可用区的工作负载优于同集群工作负载的状况,这对业务来说有可能是非预期的。
此方式的优缺点对比:
优点
缺点
优点
缺点
相比单集群部署来说,该拓扑拓展了覆盖的故障成因维度,进一步提高了系统整体的可用性。
需要将服务对等地部署在两个Kubernetes集群环境内,部署和运维复杂度较高。负载均衡、Kubernetes集群等云资源基础设施需要部署多份,成本较高。
只需要两个集群在同一VPC内部即可。当需要将流量故障转移到另一个集群中的服务时,此种部署拓扑具有较低的集群互通成本。
无法处理地域级别的故障。
在此种部署拓扑下,您需要对多个集群的网络配置进行规划、避免出现网络冲突的情况。具体操作,请参见多集群网络规划。
不建议将多集群多可用区单地域部署作为首选方案,因为其在显著增加部署运维复杂度的同时,没有带来与之相应的最高级别可用性。
多地域多集群部署。
在多集群的基础上,将单地域部署变为多地域部署。可以保证每个服务的部署在不同的维度上都是分散的:它们拥有不同的可用区、部署地域、部署集群、部署依赖。通过这种方式,可以尽可能地保证在发生任何可能原因导致的故障时,都有正常的工作负载在提供服务。
此方式的优缺点对比:
优点
缺点
优点
缺点
可以将同一服务的工作负载分散到不同地域、不同可用区、不同集群,以提高服务的可用性。
需要将服务对等地部署在两个Kubernetes集群环境内、且为了更好的推送延迟表现,服务网格实例也需要准备两份。
基于多主控制面架构,可以有效控制延迟问题。
跨地域网络互通较为复杂。
当您有高可用级别的需求时,推荐采用这种拓扑进行业务应用的部署。在需要跨集群网络打通场景下,可选用以下两种方式进行集群网络的打通:
使用云企业网直接打通跨地域集群底层网络。首先您需要对多个集群的网络配置进行规划,以避免出现网络冲突的情况。具体操作,请参见多集群网络规划。接下来,使用云企业网打通跨地域网络。具体操作,请参见跨地域连接。
使用ASM跨集群网络代理实现跨集群网络打通和故障转移,以优化资源成本并解决复杂网络互通问题。使用这种方式,两个集群的网络可以不直接互通、不需要进行集群网络规划,有关ASM跨集群网络代理的细节,请参见使用ASM跨集群网格代理实现多集群跨网络互通。
多云多地域多集群部署。
此部署拓扑是最高级别的部署拓扑方式。ASM完全支持管理任意云提供商以及线下IDC的Kubernetes集群,通过在不同云提供商之间、或是云上和云下两套Kubernetes集群环境,以保证任一基础设施在发生故障时仍可以由其他基础设施提供服务。
与多地域多集群类似,多云多地域多集群部署的方式同样需要进行集群网络的打通。但ASM无法在非阿里云环境提供托管控制面,可以使用ASM远程控制面来解决服务网格在跨云情况下的推送延迟问题。具体操作,请参见使用ASM远程控制面降低推送延迟。
此方式的优缺点对比:
优点
缺点
优点
缺点
可以将同一服务的工作负载分散到不同地域、不同可用区、不同集群、不同云厂商,以提高服务的可用性。
需要将服务对等地部署在两个Kubernetes集群环境内。同时,由于云厂商之间基础架构以及云产品能力的不同,在多云环境下的部署可能遭遇大量的兼容性以及其他未知问题。
基于多主控制面架构,可以有效控制延迟问题。
跨地域网络互通较为复杂。
容灾配置实践
以下以多地域多集群部署方式为例,演示服务级容灾实践流程。
步骤一:环境准备
在两个地域分别创建一个Kubernetes集群,命名为cluster-1和cluster-2,并且都配置了多个可用区和开启了使用EIP暴露API Server。具体操作,请参见创建ACK托管集群。
在与ACK集群相同的两个地域,分别创建ASM实例mesh-1和mesh-2,并确保创建时交换机选择了与ACK集群相同的可用区。具体操作,请参见通过ASM多主控制面架构实现多集群容灾的步骤一、步骤二与步骤三。
部署ASM网关和示例服务。
在mesh-1、mesh-2中分别创建名为ingressgateway的NLB类型入口网关,NLB可用区选择和ASM实例与ACK集群同样的两个可用区。具体操作,请参见在ASM入口网关中使用网络型负载均衡NLB。
在mesh-1、mesh-2中为两个集群的default命名空间开启Sidecar自动注入。具体操作,请参见管理全局命名空间。
在两个ACK集群内对等部署示例应用,示例使用的四个可用区分别是:cn-hangzhou-h、cn-hangzhou-k、ap-northeast-1a、ap-northeast-1b。您可以按照实际情况调整部署命令中的YAML。
上述命令分别在两个集群中执行后,会在两个集群中对等部署了一个包含名为mocka、mockb、mockc的服务的应用,每个服务下包含两个只有1副本的无状态部署,分别通过不同的NodeSelector分布到不同可用区的节点上,并通过配置环境变量来返回自己所在的可用区。
出于直观演示的目的,本示例使用了NodeSelector字段来手动选择Pod所在的可用区。在实际高可用环境的构建中,您应该配置拓扑分布约束,来保证Pod尽可能分布在不同的可用区中。具体配置方法,请参见工作负载高可用配置。
配置全局流量管理GTM,结合NLB实例实现入口网关多活容灾。具体操作,请参见GTM如何实现多活负载并容灾。
步骤二:开启基于地理位置的故障转移
ASM默认开启了基于地理位置的故障转移能力,但需要结合目标规则中设置的主机级熔断规则才可以生效。
分别在cluster-1和cluster-2集群中部署主机级熔断规则。
kubectl apply -f- <<EOF apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: mocka spec: host: mocka trafficPolicy: outlierDetection: splitExternalLocalOriginErrors: true consecutiveLocalOriginFailures: 1 baseEjectionTime: 5m consecutive5xxErrors: 1 interval: 30s maxEjectionPercent: 100 --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: mockb spec: host: mockb trafficPolicy: outlierDetection: splitExternalLocalOriginErrors: true consecutiveLocalOriginFailures: 1 baseEjectionTime: 5m consecutive5xxErrors: 1 interval: 30s maxEjectionPercent: 100 --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: mockc spec: host: mockc trafficPolicy: outlierDetection: splitExternalLocalOriginErrors: true consecutiveLocalOriginFailures: 1 baseEjectionTime: 5m consecutive5xxErrors: 1 interval: 30s maxEjectionPercent: 100 EOF
其中outlierDetection是服务网格对于服务故障的检测及故障端点驱逐机制,配置项说明如下:
配置项
说明
配置项
说明
interval
故障检测的时间。
baseEjectionTime
端点被判断为故障后,需要多久将端点从负载均衡池中驱逐。
maxEjectionPercent
最大被驱逐端点比例。
consecutive5xxErrors
端点被判断为故障前连续返回
5xx
错误的数量。splitExternalLocalOriginErrors
是否将连接失败、连接超时等情况算作故障情况。
consecutiveLocalOriginFailures
端点被判断为故障前连续产生非5xx错误(即连接失败、连接超时等情况)的数量。
验证服务状态。
向服务域名发出请求。
curl mock.asm-demo.work/mock -v
预期输出:
* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 8.xxx.xxx.47, 8.xxx.xxx.42 * Trying 8.xxx.xxx.47:80... * Connected to mock.asm-demo.work (8.209.XXX.XX) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:10:56 GMT < content-length: 153 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 3 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: ap-northeast-1b, ip: 10.1.225.40)-> mockb(version: ap-northeast-1b, ip: 10.1.225.31)-> mockc(version: ap-northeast-1b, ip: 10.1.225.32)%
可以看到,服务调用链路始终保持在同一可用区的工作负载上。
步骤三:故障演练
以下通过手动替换mockb服务在某个可用区的容器镜像来模拟工作负载故障的情况。
替换cluster-2中的mockb-ap-northeast-1a的镜像模拟故障。
登录容器服务管理控制台,在左侧导航栏选择集群列表。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择 。
选择列表中mockb工作负载右侧操作列的编辑,更换镜像为
registry.cn-hangzhou.aliyuncs.com/acs/curl:8.1.2
,同时在启动执行的命令中增加["sleep","3600"]
,让容器可以正常启动。单击更新。
持续访问应用域名,查看发生故障后的请求链路。
curl mock.asm-demo.work/mock -v
预期1:请求发送到非
ap-northeast-1a
可用区时。* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 8.209.XXX.XX, 8.221.XXX.XX * Trying 8.209.247.47:80... * Connected to mock.asm-demo.work (8.209.247.47) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:10:56 GMT < content-length: 153 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 3 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: ap-northeast-1b, ip: 10.1.225.40)-> mockb(version: ap-northeast-1b, ip: 10.1.225.31)-> mockc(version: ap-northeast-1b, ip: 10.1.225.32)%
可以看到,请求仍然保持在正常可用区内。
预期2:请求首次发送到
ap-northeast-1a
可用区时。* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 112.124.XX.XXX, 121.41.XXX.XXX * Trying 112.124.65.120:80... * Connected to mock.asm-demo.work (112.124.65.120) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:08:45 GMT < content-length: 220 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 48 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: cn-hangzhou-h, ip: 192.168.122.135)upstream connect error or disconnect/reset before headers. reset reason: remote connection failure, transport failure reason: delayed connect error: Connection refused%
可以看到,请求到达mockb服务时发生连接被拒绝的情况。
预期3:请求再次发送到
ap-northeast-1a
可用区时。* Host mock.asm-demo.work:80 was resolved. * IPv6: (none) * IPv4: 8.209.XXX.XX, 8.221.XXX.XX * Trying 8.209.247.47:80... * Connected to mock.asm-demo.work (8.209.247.47) port 80 > GET /mock HTTP/1.1 > Host: mock.asm-demo.work > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < date: Wed, 11 Dec 2024 12:10:59 GMT < content-length: 154 < content-type: text/plain; charset=utf-8 < x-envoy-upstream-service-time: 4 < server: istio-envoy < * Connection #0 to host mock.asm-demo.work left intact -> mocka(version: ap-northeast-1a, ip: 10.0.239.141)-> mockb(version: ap-northeast-1b, ip: 10.1.225.31)-> mockc(version: ap-northeast-1b, ip: 10.1.225.32)%
可以看到,请求转移到了同地域不同可用区的
ap-northeast-1b
。
(可选)步骤四:配置服务级故障产生时的告警
您可以通过配置Sidecar代理的proxyStatsMatcher,使Sidecar代理上报相关指标,然后使用Prometheus采集并查看熔断相关指标。
通过proxyStatsMatcher配置Sidecar代理上报熔断指标。在配置proxyStatsMatcher时,选中正则匹配,配置为
.*outlier_detection.*
。具体操作,请参见proxyStatsMatcher。部分熔断指标说明如下:
指标
指标类型
描述
指标
指标类型
描述
envoy_cluster_outlier_detection_ejections_active
Gauge
当前被驱逐的主机的数量。
envoy_cluster_outlier_detection_ejections_enforced_total
Counter
发生主机被驱逐事件的次数。
envoy_cluster_outlier_detection_ejections_overflow
Counter
因超过最大驱逐百分比而放弃驱逐主机的次数。
ejections_detected_consecutive_5xx
Counter
检测到主机连续产生5xx错误的次数。
重新部署httpbin无状态工作负载。具体操作,请参见重新部署工作负载。
创建针对主机级熔断的告警规则。
为数据面集群接入阿里云ASM组件或升级至最新版,以保证可观测监控Prometheus版可以采集到暴露的熔断指标。有关更新接入组件的具体操作,请参见接入组件管理。(若您已经通过集成自建Prometheus实现网格监控配置了通过自建Prometheus采集服务网格指标,则本步骤可以忽略。)
创建针对主机级熔断的告警规则。具体操作,请参见创建Prometheus告警规则。
配置告警规则的关键参数的填写示例如下,其余参数可参考上述文档根据自身需求填写。
参数
示例
说明
参数
示例
说明
自定义PromQL语句
(sum (envoy_cluster_outlier_detection_ejections_active) by (cluster_name, namespace)) > 0
示例通过查询envoy_cluster_outlier_detection_ejections_active指标来判断当前集群中是否有正在被驱逐的主机,并将查询结果按照服务所在命名空间和服务名称进行分组。
告警内容
触发主机级熔断,有工作负载连续发生错误,从服务负载均衡池中被驱逐!命名空间:{{$labels.namespace}},驱逐发生的服务:{{$labels.cluster_name}}。驱逐数量:{{ $value }}
示例的告警信息展示了触发熔断的服务所在命名空间以及服务名称,以及当前该服务被驱逐的数量。
- 本页导读 (1)
- 容灾架构
- 故障转移机制:服务网格基于地理位置的故障转移
- 应用部署拓扑:多种集群拓扑的支持方式及对比
- 容灾配置实践
- 步骤一:环境准备
- 步骤二:开启基于地理位置的故障转移
- 步骤三:故障演练
- (可选)步骤四:配置服务级故障产生时的告警