目录
- 前言
- 阅读对象
- 阅读导航
- 前置知识
- 一、什么是服务雪崩
- 1.1 基本介绍
- 1.2 解决方案
- 二、什么是Sentinel
- 2.1 基本介绍
- 2.2 设计目的
- 2.3 基本概念
- 三、Sentinel 功能和设计理念
- 3.1 流量控制
- 3.2 熔断降级
- 3.3 系统负载保护
- 四、Sentinel 是如何工作的
- 笔记正文
- 一、简单整合Sentinel
- 1.1 添加maven依赖
- 1.2 接入限流埋点:定义Sentinel资源
- 1.3 配置限流规则:定义Sentinel规则
- 1.4 设置熔断规则
- 1.4.1 Dubbo整合Sentinel
- 1.5 设置系统负载保护
- 二、概念补充:Sentinel规则
- 2.1 规则的种类
- 2.1.1 流量控制规则 (FlowRule)
- 2.1.2 熔断降级规则 (DegradeRule)
- 2.1.3 系统保护规则 (SystemRule)
- 2.1.4 访问控制规则 (AuthorityRule)
- 2.1.5 热点规则 (ParamFlowRule)
- 学习总结
- 感谢
前言
相对来说,Sentinel的学习难度比之之前的Dubbo要低了不少。不过在学习过程中也遇到了一些认知局限带来的困难。比如,虽然还是学习了Sentinel,但是不知道生产环境该如何配置才是最佳的状态。
说到底,Sentinel还是没有提供很好的文档支持。比如:生产最佳实践方案。 官方也确实提供了一个,但是总感觉不太完备。
另外在学习的过程中再次提醒了我:不要盲目的添加中间件,中间件的引入势必会造成系统复杂度上升,也带来了一定的运维成本。所以,若非有必要的,还是不要特定地去引入某个中间件吧。
最难受的是,文档资料的缺失,不少问题官网没解释,百度没答案,难受死了。
当然,这里是以学习目的出发的,就算是引入也无所谓。
阅读对象
阅读导航
系列上一篇文章:《【分布式微服务专题】从单体到分布式(三、SpringCloud整合Dubbo)》
前置知识
一、什么是服务雪崩
1.1 基本介绍
在一个高度服务化的系统中,我们实现的一个业务逻辑通常会依赖多个服务。比如:订单服务会依赖用户服务、商品服务等。此时,若其中一个服务不可用,就会导致订单服务的所有线程都因等待而引起阻塞,最终导致没有线程可用,进而引起整个服务不可用,这就是服务雪崩
导致服务不可用的可能有很多,比如:程序BUG、流量激增、缓存击穿,甚至是硬件故障。
在服务提供者不可用的时候,会出现大量重试的情况:用户重试、代码逻辑重试,这些重试最终导致进一步的流量激增,所以归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽。当服务调用者使用同步调用时, 会产生大量的等待线程占用系统资源。一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态,于是服务雪崩效应产生了
1.2 解决方案
服务雪崩常用的解决方案如下:
- 超时机制:设定接口超时时间,不做无休止的等待。属于一种缓解手段,只要流量足够大,依然有击穿的可能性
- 服务限流:限制QPS,避免流量突增而故障。属于一种预防手段
- 服务熔断降级:类似保险丝。如果某个服务调用慢,或者本身短时间内就有大量超时,那后续的请求再进来其实已经没有意义了,不如快速返回一个失败答复,避免拥挤(参考以前你抢小米手机的时候)
二、什么是Sentinel
Sentinel官方文档传送门:传送门
2.1 基本介绍
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
2.2 设计目的
流量
流量
流量
面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
2.3 基本概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
意思是,粒度可以为:进程、组件、方法,甚至是一段代码
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
三、Sentinel 功能和设计理念
Sentinel主要的功能有:流量控制、熔断降级、系统负载保护
3.1 流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
- 运行指标,例如 QPS、线程池、系统负载等;
- 控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让用户自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
3.2 熔断降级
什么是熔断降级
除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。
Sentinel 和 Hystrix 的原则是一致的:当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源进而产生雪崩的效果。
熔断降级设计理念
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:
-
通过并发线程数进行限制
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。 -
通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
3.3 系统负载保护
Sentinel 同时提供系统维度的自适应保护能力,它的最终目的是:保证系统不被拖垮的同时,进而保证系统的吞吐量。
防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
四、Sentinel 是如何工作的
Sentinel 的主要工作机制如下:
- 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析
- 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则
- Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态
从一般性流程来说,我们想要使用Sentinel来进行资源保护,主要分为几个步骤:
- 定义资源
主流框架都提供了默认的支持。例如使用SpringBoot开发的web应用,会自动定义所有http接口为Sentinel的资源
- 定义规则
这个就需要好好了解一下规则是什么,都有哪些了
- 检验规则是否生效
这个根据我目前的测试情况看来,我有点不确定官方提供的校验手段是否有效,你们看我【1.5 设置系统负载保护】内容就知道我意思了
先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。
笔记正文
我当前项目结构:
├── shenadmin // 整个服务的顶级父项目
├── shen-common // 项目公共模块
├── shen-dependencies // 项目依赖模块
├── shen-provider-apis // 项目对外暴露接口apis列表。provider直译:供应商
├── shen-order-provider-api // 订单服-对外暴露接口apis列表
├── shen-product-provider-api // 商品服-对外暴露接口apis列表
├── shen-user-provider-api // 用户服-对外暴露接口apis列表
├── shen-wallet-provider-api // 钱包服-对外暴露接口apis列表
└── shen-servers // 项目微服务列表
└── shen-product // 商品服
└── shen-order // 订单服
└── shen-user // 用户服
└── shen-wallet // 钱包服
一、简单整合Sentinel
我学习整合的教程,来自SpringCloud Alibaba整合Sentinel的sample:传送门
另外,整合之前需要做一些工具准备。
- 安装Sentinel控制台(我在【1.3 配置限流规则:定义Sentinel规则】中有提到)
- 安装JMeter压测工具
1.1 添加maven依赖
显然,只有我的微服务项目才会用到Sentinel,所以,我只需要在shen-servers
下直接添加即可。而我早先已经添加了Spring Cloud Alibaba
的管理,所以,我只需要添加依赖即可,版本由前者兼容了。
<!-- sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
1.2 接入限流埋点:定义Sentinel资源
【资源与规则】官方介绍传送门:基本使用 - 资源与规则
在此之前,需要给大家介绍并解释一下【埋点】这个概念。
Q1:什么是埋点?
埋点是一种数据采集技术,主要用于收集用户在应用或网站中的行为数据。通过在特定的页面或按钮上植入代码,可以监听用户的行为并进行收集上报。这样,开发者或数据分析师就能获取用户在使用产品过程中的具体行为数据,以进行数据分析、用户行为研究或产品优化等。简而言之,埋点是一种数据采集技术,实质是先监听软件应用运行过程中的事件,当需要关注的事件发生时进行判断和捕获。
翻译一下:【埋点】这个操作,其实在Sentinel里面,就是【定义资源】的过程。讲人话,就是设置哪些个url,甚至是方法需要被Sentinel管控。
可别刚说完就忘了Sentinel里面【资源】是什么东塞喔。我在【1.3 基本概念】中提到过,这是Sentinel里面一个核心概念
那么如何设置埋点呢?两种方式:
- 默认的
HTTP
。在Spring Cloud Alibaba
里面,默认会为所有HTTP
请求埋点,所以对我们Web开发用户来说,就不需要操心那么多了 - 自定义埋点。具体如何操作,可以参考官网的链接:基本使用(资源与规则)。不过自定义埋点操作,我稍微看了下,都是一些静态的、硬编码的方式,反正我是不喜欢这么干的。
1.3 配置限流规则:定义Sentinel规则
可得注意了啊,这里又是一个Sentinel核心概念噢。【资源与规则】官方介绍传送门:基本使用 - 资源与规则
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。
Sentinel 提供了两种配置限流规则的方式:【代码配置】和 【控制台配置】。根据官方《在生产环境中使用 Sentinel》的指引,还是建议在【控制台】中集中管理规则会比较合适,并且将规则推送之配置中心中。
本示例使用的方式为通过控制台配置。具体操作步骤如下:
1)下载安装Sentinel控制台
下载并启动Sentinel控制台。官方传送门:Sentinel 控制台
注意:控制台默认启动端口是8080,如果需要修改,启动的时候可以新增命令参数-Dserver.port=端口
。比如,我就修改为8090
端口
java -Dserver.port=8090 -jar sentinel-dashboard.jar
2)增加Sentinel配置
在所有的微服务应用中添加如下配置:
spring:
cloud:
sentinel:
transport:
# 下面的端口,
dashboard: localhost:8090
因为我已经引入了Nacos配置中心,然后这个配置在我的实验环境中,应该是共享的,所以我就配置到了我在Nacos的application-conf.yaml
文件中。如下所示:
3)重启所有微服务
4)验证安装
上述步骤完成之后,就可以打开http://localhost:8090/尝试访问了。如下所示:
注意,如果您在控制台没有找到应用,请调用一下进行了 Sentinel 埋点的 URL 或方法,因为 Sentinel 使用了【懒加载】策略。
5)配置限流规则
我在我的实验环境这种,选择了shen-wallet
,然后点击流控规则
,新增流控规则
,内容如下:
为了让效果更明显,我做了如上的配置,意思是:当前/wallet/list
接口1秒内最大访问次数。
6)简单验证
快速刷新访问http://localhost:9032/wallet/list
,会出现如下所示的结果:
正常结果:
限流结果:(Blocked by Sentinel (flow limiting))
hold on hold on,我当然是比较建议下载JMeter来测试的,我自己就简单测试了
1.4 设置熔断规则
啊,很尴尬的一个点。如果你们的PRC使用的是OpenFeign
,那么可以直接参考这个官方示例,我截图给大家看吧。
但是,我在我的整合方案中,RPC使用的是Dubbo框架的Dubbo协议,所以,我得另外配置才能实验这个特性了。
1.4.1 Dubbo整合Sentinel
Dubbo整合Sentinel很简单,就是引入一个maven依赖就好了
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>版本</version>
</dependency>
通过引入这个项目,所有Dubbo接口也会被自动【埋点】。后面的所有规则设置,跟上面介绍的操作基本是一样的。给你们看看我的效果:
1)Dubbo接口被Sentinel管理
2)对Dubbo资源做降级处理
1.5 设置系统负载保护
这一点我暂时搁置一下,MD,卡了我一天了,从昨天到现在,我不知道自己哪里没有设置对。
反正就是没效果。不知道是不是版本的问题,我百度别人的Sentinel Admin跟我的不是很像。为了校验我的规则是否生效,我采用了如下方式:
- 通过端点信息查看,规则是设置成功的(Endpoint)
- 我设置了最简单的入口QPS限制,通过压测工具发送N多条请求发现调用是成功的,反过来证明我的系统负载设置失败
- 通过实时监控发现,
b_qps
指标又是正常的,证明系统负载设置成功 - 根据秒级监控日志,看每个指标也是合理的,证明系统负载设置成功
- 自定义了BlockedException想要捕获异常日志,但是没有发现系统保护异常
SystemBlockException
暂时性放弃了xdm
二、概念补充:Sentinel规则
我在学习的过程中,发现,Sentinel的规则还是非常重要的,只有熟练的掌握了这些规则,我们才能在实际的生产中,做更丰富的流控策略。
2.1 规则的种类
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
总的来说,Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。
2.1.1 流量控制规则 (FlowRule)
重要属性:
PS:同一个资源可以同时有多个限流规则
通过代码定义流量控制规则:
理解上面规则的定义之后,我们可以通过调用 FlowRuleManager.loadRules()
方法来用硬编码的方式定义流量控制规则,比如:
private static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource(resource);
// Set max qps to 20
rule1.setCount(20);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
2.1.2 熔断降级规则 (DegradeRule)
重要属性:
PS:同一个资源可以同时有多个降级规则
通过代码定义熔断降级规则:
理解上面规则的定义之后,我们可以通过调用 DegradeRuleManager.loadRules()
方法来用硬编码的方式定义流量控制规则。
private static void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule(resource);
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
.setCount(0.7); // Threshold is 70% error ratio
.setMinRequestAmount(100)
.setStatIntervalMs(30000) // 30s
.setTimeWindow(10);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
2.1.3 系统保护规则 (SystemRule)
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
重要属性:
通过代码定义系统保护规则:
理解上面规则的定义之后,我们可以通过调用 SystemRuleManager.loadRules()
方法来用硬编码的方式定义流量控制规则:
private void initSystemProtectionRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(10);
rules.add(rule);
SystemRuleManager.loadRules(rules);
}
2.1.4 访问控制规则 (AuthorityRule)
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的访问控制(黑白名单)的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
授权规则,即黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:
resource
:资源名,即限流规则的作用对象limitApp
:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appBstrategy
:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式
2.1.5 热点规则 (ParamFlowRule)
热点规则的配置略显麻烦一点。首先需要理解,什么是热点
热点:
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
限流原理:
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控
在我们项目中,如果想要使用改规则,还需要额外引入maven依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>x.y.z</version>
</dependency>
重要属性:
学习总结
感谢
- 感谢Alibaba Sentinel的文章《在生产环境中使用 Sentinel》