微服务治理实践:如何对单点异常进行自动摘除

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 微服务架构下,稳定性和高可用性一个永恒的话题,在实际的治理过程中,我们有可能会遇到以下场景: 某个应用灰度发布,先上了几台机器,由于代码逻辑写的有问题,造成线程池满,出现运行异常。 服务端集群中,某几台机器由于磁盘满,或者是宿主机资源争抢导致 load 过高,客户端出现调用超时。

直播回顾:点击这里

微服务架构下,稳定性和高可用性一个永恒的话题,在实际的治理过程中,我们有可能会遇到以下场景:

  • 某个应用灰度发布,先上了几台机器,由于代码逻辑写的有问题,造成线程池满,出现运行异常。
  • 服务端集群中,某几台机器由于磁盘满,或者是宿主机资源争抢导致 load 过高,客户端出现调用超时。
  • 服务端集群中,某几台机器由于线程池满,造成 Full Garbage Collection。

在以上 3 种场景中,由于客户端并不法感知已经出现问题的那些服务端,依然会发送请求到这些机器上,造成业务调用报错,上游的机子将会被下游的某台机子的短暂故障拖垮,造成应用雪崩的风险。

面对这种场景,如果仅仅为此而进行服务降级,对应用的伤害未免过大,但如果我们可以检测出服务集群中某些故障机子,并对其进行短暂隔离,即可有效保障服务的高可用与系统的稳定性,同时给运维人员提供了宝贵的缓冲时间,用于问题定位,排除故障。

本文将作为《微服务治理实践》系列篇的第一篇,为大家介绍如何实现离群实例摘除。该系列文章是基于阿里云商业化产品 EDAS 的微服务实践,如果您团队具备较强的微服务治理能力,那么希望我们在微服务治理方面的实践和背后的思考,可以为您提供一些参考。

企业级分布式服务 EDAS 重磅升级,12月17日下午15:00--17:00中间件小师妹在直播间等你,携开发工程师十眠为您详细介绍 EDAS 离群实例摘除等微服务治理能力。还有礼品送不停,直播间地址点击“传送门”。

Microservice Outlier Ejection (微服务离群实例摘除)

  • 什么是离群实例摘除

当单点发生夯机异常时,consumer 能主动判断,并将对应的 provider 实例短时间剔除,不再请求,在一定时间间隔后再继续访问。同时,具有全局异常判断能力,当 provider 异常实例的数量过多时,并且超过一定的控制比例,说明此时 provide 整体服务质量低下,该机制仅保持摘除一定的比例。

  • 离群实例摘除的功能

从服务层容错能力上,对业务稳定性进行增强,有效解决单点故障的问题。

  • 与熔断的区别

熔断是指当服务的输入负载激增时, 避免服务被迅速压垮导致雪崩效应,而对负载进行断路的一种方式 。 熔断一般由熔断请求判断算法,熔断恢复机制,熔断报警等模块组成。隔离是指,为了避免在依赖的服务故障时候造成的故障扩散,而采取的将系统进行单元化设计的一种架构方法。

若仅仅由于服务端集群中单点异常问题,就采用熔断降级方案,将会对应用的伤害过大,离群实例摘除可以有效地解决单点异常问题从而保证服务质量。若 provider 整体服务质量低下时,离群摘除效果不再明显,此时可以采用熔断降级功能。

  • 离群实例摘除支持的版本

只要您的应用版本在列表中,您无需改动一行代码就可以使用到离群实例摘除功能。

目前支持版本 开发中版本(即将支持)
Dubbo 2.5.0~2.7.3 < 2.5.0 dubbox 版本
Spring Cloud D、E、F、G、H C

目前已经覆盖了市面上大部分微服务场景,后续我们将会持续支持开源最新的 Dubbo/Spring Cloud 版本。

我们提供了 Dubbo 和 Spring Cloud 两种场景的离群摘除功能,本文将先介绍一下 Dubbo Microservice Outlier Ejection 的实践与效果。

下面将通过在 EDAS 上通过演示 Dubbo 离群摘除功能及效果。

企业级分布式应用服务EDAS(Enterprise Distributed Application Service)是一个应用托管和微服务管理的 PaaS 平台,提供应用开发、部署、监控、运维等全栈式解决方案,同时支持 Dubbo、Spring Cloud 等微服务运行环境。

https://www.aliyun.com/product/edas

准备

接下来以微服务Demo为例子示范离群摘除功能,读者可以从github中下载验证

https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/src

微服务Demo是一个简单的电商项目,下图为项目结构,cartservice 为 Dubbo 框架的购物车服务 provider,productservice 为Spring Cloud提供的商品详情服务 provider,frontend 为web controller即前端展示页面,可以理解为consumer。

1

我们将以cartservice服务即Dubbo服务端为例子,展示离群实例摘除功能。

EDAS 上部署微服务 Demo

首先 cd cartservice切换到 cartservice 目录下,再通过 mvn clean install 打包,通过 cd cartservice-provider/target 切换到target目录下,我们可以看到新生成的 cartservice-provider-1.0.0-SNAPSHOT.jar 包,然后在 EDAS上 创建一个 cartservice 应用。

3

点击下一步后,上传刚才打包的jar包,即 cartservice-provider/target/ cartservice-provider-1.0.0-SNAPSHOT.jar 然后下一步,记住登陆密码,直到创建应用成功。

4

然后启动应用,到目前为止,我们启动了一个 cartservice-provider。点击按此实例规格扩容,该服务我们部署在两个实例上。
lADPDgQ9rWd_0YNLzQLq_746_75_jpg_620x10000q90g

我们在这个 provider 的 com.alibabacloud.hipstershop.provider.CartServiceImpl 类中可以看到,这个 provider 是提供了viewCart 和 addItemToCart 的两个关于购物车的服务,我们在 viewCart 中加入一些模拟运行时异常的逻辑。

    @Value("${exception.ip}")
    private String exceptionIp;

    @Override
    public List<CartItem> viewCart(String userID) {

        if (exceptionIp != null && exceptionIp.equals(getLocalIp())) {
            throw new RuntimeException("运行时异常");
        }

        return cartStore.getOrDefault(userID, Collections.emptyList());
    }

其中 exceptionIp 为 ACM 配置中心的exception.ip的配置项,若该项配置为本机ip时,该服务throw RuntimeException,用于模拟业务异常的场景。

  • 为什么将 cartservice 扩容到两个实例,想必大家也猜到了,运行时通过配置ACM配置中心指定其中一个实例的IP,模拟出一个实例异常的场景。

接下来,我们需要部署 frontend / productservice 两个服务,方式一样,分别上传 frontend/target/frontend-1.0.0-SNAPSHOT.jar 和 productservice/productservice-provider/target/productservice-provider-1.0.0-SNAPSHOT.jar

从下图可以看到,我们的微服务Demo在EDAS部署上去了。

6

模拟业务异常

进入到 frontend 应用中,我们看到其实例的公网 ip 为 47.99.150.33。
lADPDgQ9rWeBe494zQLq_746_120_jpg_620x10000q90g

进入浏览器访问 http://47.99.150.33:8080/

8

点击View Cart 访问至 http://47.99.150.33:8080/cart

9
可以看到,此时服务都是正常的。

我们去 ACM 配置中心 配置 exception.ip 为 172.16.205.180(即cartservice的其中某个实例的IP)。
10

然后继续访问 http://47.99.150.33:8080/cart ,发现 50 % 的概率错误页面

11

此时,我们写一个脚本,定时大量访问 http://47.99.150.33:8080/cart 模拟请求。

while :
do
        result=`curl $1 -s`
        if [[ "$result" == *"500"* ]]; then
                echo `date +%F-%T` $result
        else
                echo `date +%F-%T` "success"
        fi

        sleep 0.1
done

然后 sh curlservice.sh http://47.99.150.33:8080/cart

我们看到不断重复的每秒钟 10 次的 50% 的调用成功率。

12

其实也可以理解到,下游的服务质量随着上游的某台机子的异常而急剧下降,甚至可能导致下游服务被上游某些机子的(系统、业务)异常给拖垮。

开启离群摘除策略

下面我将演示离群摘除的策略的开启及其效果的展示。

创建

我们进入到 EDAS 左侧列表的 [微服务管理] 下的 [离群实例摘除] 界面中,并选择创建离群实例摘除策略。

13

然后按照提示一步步创建离群摘除的策略。

基本信息

14

如上图可以选择命名空间、填写策略名称、选择该策略支持的框架类型(Dubbo/Spring Cloud)。

选择生效应用

15

按照目前的调用方式,我们只需要配置 frontend 应用,保护下游应用 consumer。

配置策略

16

这些参数都提供了默认值,需要根据自己应用的具体情况调整最合适的值,由于需要保护的 RuntimeException 属于业务异常于是选上 网络异常+业务异常。(需要注意的是即使摘除实例比例上限配得特别低,向下取整数小于1,当集群中实例数目大于1,且某一实例异常,我们也会摘除一实例)。

创建完成

17

可以看到策略的信息,创建完成。

策略

18

看到了我们创建的离群摘除策略,且是针对Dubbo框架,并且针对的是 网络异常+业务异常 的异常类型。

验证离群摘除效果

这时,我们看到,再感知到异常后,离群摘除功能生效,请求调用一阵子后,均返回正确结果。

19

不断刷新浏览器访问 http://47.99.150.33:8080/cart 也均正常
20

客户端感知到某台服务端机子异常后,主动摘除。仅仅调用业务正常的 Provider 实例,同时我们也可以通 ARMS(EDAS监控系统) 监控看到服务质量的上升,以及流量从异常 Provider 中摘除。

Dubbo框架可以从 /home/admin/.opt/ArmsAgent/logs 目录下的日志中,搜索日志中的 “OutlierRouter” 关键字可以看到一系列离群实例摘除的事件日志。

修改/关闭离群摘除策略

对于EDAS的应用我们支持通过控制台动态修改和删除离群摘除策略。

  • 对应策略规则的修改

点击 修改生效应用 或者 编辑策略。

21

然后增加删除应用或者调整参数,确定后均立即生效

  • 删除对应策略

22

控制台的操作,对应用中的配置都是实时生效的,若删除策略后,默认关闭相关策略。

若我们打开ARMS监控观察具体的调用情况。

ARMS监控

若我们开启监控,将会直观看到流量与请求错误等信息。

开启离群摘除前

如下图方式开启,然后跳转至ARMS(EDAS监控系统)应用监控页面,我们需要把三个应用都开启高级监控。
23

我们可以从下图即ARMS(EDAS监控系统)应用监控页面直观地看到结果。

24

从以下拓扑图中我们看到,流量不断地访问到cartservice服务上。

25

开启离群摘除后

离群摘除效果通过简单的例子就看到了,当然可以通过 ARMS (EDAS监控系统)的监控可以明显观察到服务质量的提升。

29

可以看到,在开启了离群摘除的那个点只后,错误率从50%明显下降。

26

其中两个小的起伏毛刺是因为,离群摘除一段时间后会重新尝试访问被摘除的 endPoint ,若依旧错误率高于阈值,继续隔离,且间隔时间更长。

离群实例摘除具体控制逻辑

前面我们看到了,离群实力摘除对应用稳定性提高带来的帮助,下面我们将具体分析离群实例摘除的控制逻辑,有助于您更好地理解其各种参数的意义,以及可以根据自己的应用情况,通过调整参数,配置出最合适自己的离群摘除策略。

对于 Dubbo/SpringCloud 框架:

  • 默认QPS下限为1

只有当前某实例的调用QPS大于1才会开始离群实例摘除保护。

  • 默认错误率下限 50%

只有当前某实例的调用错误率高于 50% ,则系统会认为该服务端集群的当前某实例处于异常状态。

  • 默认摘除实例比例上限 20%

若当前服务集群中,有大于20%的实例节点处于异常状态,则系统只会摘除异常状态的实例数占集群总数的50%。

  • 异常类型

若异常类型为 网络异常 ,则系统仅仅把网络异常的错误算进错误率统计中,忽略掉业务异常;反之,若选择了 网络异常 + 业务异常 则系统会将所有异常当成错误算进错误率统计中。

  • 关于恢复检测单位时间(默认30000ms即30s)与未恢复累计次数上限(默认40)的解释

其中第一次摘除时长为 0.5 分钟,时间到了之后 consumer 会继续访问该 provider ,若该 provider 服务质量依旧低下,则会继续摘除,摘除时长随着连续被摘除次数的增加线性递增每次增加 0.5 分钟,每次最多摘除 20 分钟。当然,若继续调用之后,服务质量恢复了,则会当成健康服务,下一次又出现异常导致服务质量低下问题时,会重新隔离 0.5 分钟,并继续上述规则。

  • 兜底

但是当客户端调用的服务仅有1个实例提供服务提供则不会隔离这个实例。

若当前客户端调用的服务实例大于1个,且当前离群摘除隔离比例计算出的实例数小于1,若服务端集群出现单点故障,则会摘除1个实例。

上面所有的实例可以理解为endpoint(ip+port为纬度)

  • 通用最佳实践

可以配置相对的错误率阈值(50%)与过低的摘除实例比例上限(10%),全链路开启。

离群实例摘除技术细节

无侵入技术

无侵入方案即通过agent技术来实现,一句话来说就是通过字节码增强技术,运行时插入我们的代码,改变应用的原有逻辑,可以理解为运行时AOP,通过在Dubbo的链路中插入Filter/Router,在Spring Cloud中增强LoadBalance逻辑,来实现我们期望的路由控制逻辑。同时因为是agent增强的,再加上 Dubbo 各个版本的链路整体基本没大的变化,Spring Cloud 模型的统一性,因此我们可以花少的代价将能力基本覆盖到所有版本。
27

Dubbo Agent 方案技术架构

对于用户来说,无需改动一行代码,一行配置,即可享受到稳定性增强的能力。

离群实例摘除技术

Outlier Detection 离群检测

均是基于时间窗口的数据统计。

两种实现
1、Dubbo 2.7 版本通过向链路中嵌入一个MetricsFilter,对于链路的每个request/response做打点处理,统计rt、调用成功与否、异常类型,并且已endpoint(ip+port)为key存储

2、在 Agent 底座中统计经过的http请求,通过url、rt、状态码、异常类型等数据结果,统计最近时间窗口的数据(目前写死 10 秒,暂时不透出)

实时统计前N秒的调用信息,作为离群实例摘除动作的依据。

Outlier Ejection 离群摘除

Dubbo 基于 Dubbo Router 实现,对于调用的上游服务对应的所有 invokers 中,拉黑掉“不健康”的节点,同时记录拉黑的信息。

28

Dubbo-Router控制逻辑
每次请求过来仅仅check一下并标记状态,后台有专门两个线程将标记的流量进行判断是否进入隔离列表或从中剔除,修改拉黑信息等耗时操作,最大程度上保证请求的实时性。

Spring Cloud 基于 扩展 LoadBalace 实现,原理相似。

微服务商业化团队招人了~

Dubbo / Spring Cloud 商业化,我们除了 EDAS,我们还有 ARMS(应用实时监控服务)、MSE(微服务引擎)、ACM(应用配置管理)、SAE(Serverless 应用引擎)等独立产品。我们在忙什么?用心打磨这些产品,就是我们的工作。

团队的目标是将阿里巴巴在服务治理上的最佳实践通过产品化的形式输出给阿里云上的企业客户,帮助客户实现业务永远在线。

招聘邮箱: shengwei.psw@alibaba-inc.com

作者信息:泮圣伟,花名十眠,中间件技术-微服务产品团队研发工程师,负责 Dubbo / Spring Cloud 商业化产品开发相关工作,目前主要关注云原生、微服务等技术方向。

相关实践学习
通过云拨测对指定服务器进行Ping/DNS监测
本实验将通过云拨测对指定服务器进行Ping/DNS监测,评估网站服务质量和用户体验。
相关文章
|
21天前
|
API 持续交付 开发者
后端开发中的微服务架构实践与挑战
在数字化时代,后端服务的构建和管理变得日益复杂。本文将深入探讨微服务架构在后端开发中的应用,分析其在提高系统可扩展性、灵活性和可维护性方面的优势,同时讨论实施微服务时面临的挑战,如服务拆分、数据一致性和部署复杂性等。通过实际案例分析,本文旨在为开发者提供微服务架构的实用见解和解决策略。
|
22天前
|
弹性计算 Kubernetes Cloud Native
云原生架构下的微服务设计原则与实践####
本文深入探讨了在云原生环境中,微服务架构的设计原则、关键技术及实践案例。通过剖析传统单体架构面临的挑战,引出微服务作为解决方案的优势,并详细阐述了微服务设计的几大核心原则:单一职责、独立部署、弹性伸缩和服务自治。文章还介绍了容器化技术、Kubernetes等云原生工具如何助力微服务的高效实施,并通过一个实际项目案例,展示了从服务拆分到持续集成/持续部署(CI/CD)流程的完整实现路径,为读者提供了宝贵的实践经验和启发。 ####
|
4天前
|
监控 持续交付 API
深入理解微服务架构:从设计原则到实践应用
深入理解微服务架构:从设计原则到实践应用
|
11天前
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
36 5
|
14天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
9天前
|
Kubernetes API Docker
构建高效后端服务:微服务架构的深度实践与优化####
本文深入探讨了微服务架构在现代后端开发中的应用,通过剖析其核心概念、设计原则及实施策略,结合具体案例分析,展示了如何有效提升系统的可扩展性、可靠性和维护性。文章还详细阐述了微服务拆分的方法论、服务间通信的最佳实践、以及容器化与编排工具(如Docker和Kubernetes)的应用技巧,为读者提供了一份全面的微服务架构落地指南。 ####
|
12天前
|
负载均衡 监控 Cloud Native
云原生架构下的微服务治理策略与实践####
在数字化转型浪潮中,企业纷纷拥抱云计算,而云原生架构作为其核心技术支撑,正引领着一场深刻的技术变革。本文聚焦于云原生环境下微服务架构的治理策略与实践,探讨如何通过精细化的服务管理、动态的流量调度、高效的故障恢复机制以及持续的监控优化,构建弹性、可靠且易于维护的分布式系统。我们将深入剖析微服务治理的核心要素,结合具体案例,揭示其在提升系统稳定性、扩展性和敏捷性方面的关键作用,为读者提供一套切实可行的云原生微服务治理指南。 ####
|
14天前
|
Kubernetes Cloud Native Docker
云原生技术探索:容器化与微服务的实践之道
【10月更文挑战第36天】在云计算的浪潮中,云原生技术以其高效、灵活和可靠的特性成为企业数字化转型的重要推手。本文将深入探讨云原生的两大核心概念——容器化与微服务架构,并通过实际代码示例,揭示如何通过Docker和Kubernetes实现服务的快速部署和管理。我们将从基础概念入手,逐步引导读者理解并实践云原生技术,最终掌握如何构建和维护一个高效、可扩展的云原生应用。
|
15天前
|
监控 API 持续交付
后端开发中的微服务架构实践与挑战####
本文深入探讨了微服务架构在后端开发中的应用,分析了其优势、面临的挑战以及最佳实践策略。不同于传统的单体应用,微服务通过细粒度的服务划分促进了系统的可维护性、可扩展性和敏捷性。文章首先概述了微服务的核心概念及其与传统架构的区别,随后详细阐述了构建微服务时需考虑的关键技术要素,如服务发现、API网关、容器化部署及持续集成/持续部署(CI/CD)流程。此外,还讨论了微服务实施过程中常见的问题,如服务间通信复杂度增加、数据一致性保障等,并提供了相应的解决方案和优化建议。总之,本文旨在为开发者提供一份关于如何在现代后端系统中有效采用和优化微服务架构的实用指南。 ####
|
17天前
|
消息中间件 设计模式 运维
后端开发中的微服务架构实践与挑战####
本文深入探讨了微服务架构在现代后端开发中的应用,通过实际案例分析,揭示了其在提升系统灵活性、可扩展性及促进技术创新方面的显著优势。同时,文章也未回避微服务实施过程中面临的挑战,如服务间通信复杂性、数据一致性保障及部署运维难度增加等问题,并基于实践经验提出了一系列应对策略,为开发者在构建高效、稳定的微服务平台时提供有价值的参考。 ####
下一篇
无影云桌面