Sentinel-dashboard官方下载地址:https://github.com/alibaba/Sentinel/releases
下载jar包
SpringCloud Alibaba 官方版本说明:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
Spring Cloud Alibaba Sentinel官网文档:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
注意:
Sentinel-dashboard需要在JDK1.8及以上的版本登录
由于Sentinel-dashboard使用Springboot写的一个项目,所以默认是集成了Tomcat,但是Sentinel-dashboard的端口号默认是8080与Tomcat冲突,
所以启动的时候需要修改端口号。
这里使用
8090
端口作为访问Snetinel-dashboard的管理页面的端口号
【不指定输出日志的命令示例】
java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar 【jar包的名称】
【指定输出日志的命令】
java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -Dcsp.sentinel.log.dir=C:logssentinel-dashboard -jar 【jar包的名称】
Sentinel-dashboard的登录密码和账户:
账户: sentinel
密码: sentinel
用户可以通过如下参数进行鉴权配置:
注意:部署多台控制台时,session 默认不会在各实例之间共享,这一块需要自行改造。
这里说明一下:我们如果想要自定义一个Sentinel-dashboard的项目,则可以通过启动时配置一定的启动参数来完成,具体如下:
java -Dserver.port=8070 -Dcsp.sentinel.dashboard.server=localhost:8070 -Dproject.name=sentinel-helloworld -jar 【jar包的名称】
这里是指定一个名称为sentinel-helloworld的项目,
然后在eclispe里面通过配置JVM启动参数来实现将服务的流量监控数据同步到sentinel-dashboard的控制面板上
-Dcsp.sentinel.dashboard.server=localhost:8070
-Dproject.name=sentinel-helloworld
启动完成后,多刷新几次,保证数据同步过来,也可以测试几次失效流量控制的情况
出现问题: 但是这样子有的情况下我也不清楚具体原因是什么,就是出不来,然后我就重新引入了 另外的Sentinel的依赖
解决问题:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
通过配置文件的方式来完成dashBoard的搭建
spring:
cloud:
sentinel:
transport:
port: 8071 #跟控制台交流的端口,随意指定一个未使用的端口即可
dashboard: localhost:8070 # 指定控制台服务的地址
这时候我们再次重启Sentinel-dashboard和HelloWorld的这个项目
访问localhost:8080
登录,多次刷新应用程序
然后后来我有用Idea去使用我第一次的写法尝试后,是没有问题的,可能是我的Eclispe配置的问题,总之,是成功搭建完成了Sentinel-dashboard的环境
上一篇的末尾写了一个使用代码的方式编程完成流量控制的方式。
但是在日常的开发中,我们也需要使用到管理端完成流控规则的设置。
这里我们把编程式的流量控制规则代码注释掉以后,再次访问http://localhost:8090/hello,去到Sentinel-dashboard,我们发现此时无论我们怎么刷新,此时都不会出现流量控制的现象。
注意:
这里的资源名是我们通过SphU.entry("Hello World")
来设置的资源名,必须哟啊保证一致,否则无法生效
这是我们保存后,再次刷新,可以发现就有了流量控制的监控。
资源是Sentinel的关键概念。它可以是Java引用程序中的任何内容,例如:有应用程序提供的服务,或者是引用程序调用的其他应用程序,甚至可以是一段代码,在接下来的文档中,我们都会使用资源来描述迭代代码。
只要通过Sentinel API定义的代码,就是资源。能够被Sentinel保护起来,大部分情况下,可以使用方法签名,URL,甚至是服务名作为资源的标识来唯一的定位某一个资源。
使用Sentinel来进行资源保护,主要分为以下几个步骤:
只要有了资源,就可以在任何时候灵活的定义各种流量控制的规则。
在编码的时候,我们只需要考虑是否需要对其进行流控。如果需要则先把这个定义为一个资源。
为了减少开发过称中的复杂度,Sentinel对大多数的主流框架都有默认的适配,例如:Dubbo,SpringCloud,Web Servlet等等。,我们只需要引入对应的依赖即可方便的整合Sentinel。
SphU
就是包含了try-catch风格的API,用这种方式,当资源发生了限流以后会抛出BlockException,这时候,我们就可以进行限流之后的逻辑操作
try (Entry hai = SphU.entry(资源名称)) {
// 被保护的代码逻辑
} catch (BlockException e) {
e.printStackTrace();
// 降级处理的代码逻辑
}
SphO
提供if-else风格的API,这种方式,当资源发生了限流之后会返回false,这个时候可以通过返回值,进行限流之后的逻辑操作,示例代码:
// 资源名可以使用任意类型的业务语义的字符串
if (SphO.entry("自定义的资源名")) {
// 务必保证finally会被执行 也就是catch代码块可以没有,但是finally代码快必须有
try {
/*
被保护的业务逻辑
*/
}finally {
SphO.exit();
}
}
注意:SphO.entry(xxx) 需要与SphO.exit()方法成对出现,匹配调用,位置正确。
否则会导致调用链记录异常。抛出ErrorEntryFreeExecption异常
使用@SentinelResurce
注解来定义资源。
Sentinel支持通过SentinelResource注解来定义资源,并提供了AspectJ的扩展用来自定义资源,处理BlockException等,使用Sentinel Annotation Aspect Extension 的时候需要引入一下依赖:
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-annotation-aspectjartifactId>
dependency>
Spring Cloud Aibaba
若您的应用是通过SpringCloud Alibaba
接入的,则无需额外的进行配置即可使用@SentinelResource注解
Spring Boot
如你的应用使用的是Spring Aop(无论是Spring Boot还是传统的Spring应用)
,我们都需要以配置的方式将SentinelresourceAspect注册为一个SpringBean
;
@Configuration
public class SentinelAspectJConfig {
// 需要一个SentinelResourceAspect的类,完成对注解式的流控规则的支持
@Bean
public SentinelResourceAspect getAspect() {
return new SentinelResourceAspect();
}
}
@RequestMapping("/hello3")
@SentinelResource(value = "HelloWei", blockHandler = "blockHandlerForHello3")
public String hello3() {
return "Sentinel 注解方式流量控制,@SentinelResource" + System.currentTimeMillis();
}
/**
* 原方法调用被限流/降级/系统的保护时候用
* @param exception
* @return
*/
public String blockHandlerForHello3(BlockException exception) {
exception.printStackTrace();
return "系统繁忙,请稍后!!!";
}
@SentinelResource注解里 提供了两个违规处理的方法blockHandler和fallback
区别:
- fallback管理的是java运行异常。
- blockHandler管sentinel的控制台违规配置。
若blockHandler和fallback都进行了配置,则被限流降级而抛出BlockException时只会进入blockHandler处理逻辑。
Sentinel支持异步调用链路的统计。在异步调用中,通过SphU.asyncEntry(xxx)的方式定义资源,并通过需要在异步的回调函数中调用exit方法。
@SpringBootApplication
// 让项目支持异步调用
@EnableAsync
public class SentinelHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelHelloWorldApplication.class, args);
}
}
Service层代码逻辑
@Service
public class AsyncService {
@Async
public void doAsyncMethod() {
System.out.println("Async Method is Starting...");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Async Method is ending...");
}
}
Controller层调用
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/async")
public String asyncController() {
// 定义一个异步调用的Entry
AsyncEntry asyncEntry = null;
try { // 被保护的代码逻辑
asyncEntry = SphU.asyncEntry("HelloAsync");
asyncService.doAsyncMethod();
} catch (BlockException e) { // 流量控制后的处理逻辑
// TODO Auto-generated catch block
System.out.println("系统繁忙,请稍后重试...");
e.printStackTrace();
}finally {
if (asyncEntry!=null) {
asyncEntry.exit();
}
}
return "Async Method is execuate!";
}
}
总结:
Sentinel的所有的规则都可以用在内存态中动态的查询及修改,修改之后立即生效,不好会有延迟。同时Sentinel也提供相关API,供我们来定制自己的规则策略。Sentinel支持以下几种规则:
流量控制(Flow Control): 其原理是监控应用流量的QPS或者并发线程等指数,当达到指定的阈值时候,对流量进行控制,以避免瞬时的高峰访问流量冲垮服务,从而保障高可用性。
重要属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | – |
count | 限流阈值 | – |
grade | 限流阈值的类型,QPS模式(1)后者开发线程的模式(0) | QPS模式 |
limitApp | 流控针对的调用来源 | defalut,代表不区分调用来源 |
strategy | 调用关系限流策略:直接,链路,关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝/WarmUp/匀速+排队等待) ,不支持调用关系限流 | 直接拒绝 |
clusterMode | 是否集群限流 | 否 |
限流类型分为:
流控模式:
当helloworld3的QPS超过2的时候,helloworld失效
流控效果:
让通过的流量缓慢增加,在 一定时间内逐渐增加到阈值上限
。给冷却系统一个预约的时间,避免冷却系统压垮。也即是是让请求以匀速通过
,对应的是漏桶算法。总结流量控制效果:
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。
一个服务 常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方API等。 例如,支付的时候,可能需要远程调用银联提供的API ;查询某个商品的价格,可能需要进行数据库查询。
然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
在大型的分布式应用中,我们可能会存在多个服务之间存在着比较复杂的调用关系,但是,我们无法保证在某一时刻某一个服务不会崩掉,为了保证整个服务不会被这一个子服务拖累,所以我们就需要对这个不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用。避免了局部不稳而导致整体不稳的情况。
Sentinel1.8.0版本及以上,对熔断降级的特性有了一个全新的升级
,所以,我们最好是使用Sentinel1.8.0及以上的版本,这样学习成本会比较低。
Sentinel提供以下几种熔断策略:
请求的响应时间大于该值则统计为慢调用。当单位统计时长( statIntervaMs )内请求数目大于设置的最小请求数目, 并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。
经过熔断时长后熔断器会进入探测恢复状态( HALF-OPEN状态) , 若接下来的一个请求响应时间小于设置的慢调用RT则结束熔断,若大于设置的慢调用RT则会再次被熔断。注意异常降级仅针对业务异常,对Sentinel限流降级本身的异常( BlockException )不生效。为了统计异常比例或异常数,需要通过 Tracer. trace(ex)记录业务异常。示例:
同一个资源可以有多个降级规则,了解了上面的规则之后,我们可以通过DegradeRuleManager.loadRules(rule)的方式来规定降价规则
/**
* 熔断规则的定义代码实例
*/
private void initDegardeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
rule.setResource("Circuit breaking"); //设置熔断资源
rule.setCount(10); // 熔断比例阈慢调用比例RT
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // 熔断策略
rule.setMinRequestAmount(5); // 熔断触发的最小请求数
rule.setTimeWindow(10); // 熔断时长 单位为s
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
熔断器事件监听
Sentinel支持注册自定义的时间监听器监听熔断器状态变化事件(State Change event):实例:
Sentinel 系统自适应限流瓜整体维度对应用入口流量进行控制,结合应用的Load、CPU 使用率、总体平均 RT、入口QPS和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统规则包含下面几个重要的属性:
了解了上面的规则定义以后,我们就可以通过调用SystemRuleManager.loadRules()方法来硬编码的方式定义流控规则
private void initSystemRule(){
List<SystemRule> rules = new ArraList<>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(10);
rules.add(rule);
SystemRuleManager.loadRules(rules);
}
在开始之前,我们先了解一下系统保护的目的:
长期以来,系统保护的思路是根据硬指标,即系统的负载(load1)来做系统过载保护。当系统负载高于某个阈值,就禁止或者减少流量的进入;当load开始好转,则恢复流量的进入。这个思路给我们
带来了不可避免的两个问题:
TCP BBR
的思想给了我们一个很大的启发。我们应该根据系统能够处理的请求,和允许进来的请求。 来做平衡,而不是根据一个间接的指标(系统load )来做限流。最终我们追求的目标是在系统不被拖垮的情况下,提高系统的吞吐率,而不是load一定要到低于某个阈值。 如果我们还是按照固有的思维,超过特定的load就禁止流量进入,系统load恢复就放开流量,这样做的结果是无论我们
怎么调参数,调比例,都是按照果来调节因,都无法取得良好的效果。
Sentinel在系统自适应保护的做法是,用load1作为启动自适应保护的因子,而允许通过的流量由处理请求的能力,即请求的响应时间以及当前系统正在处理的请求速率来决定。
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用Sentinel的来源访问控制( 黑白名单控制)的功能。来源访问控制根据资源的请求来源( origin )限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
调用方信息通过
ContextUtil.entery (resourceName, origin)
方法中的origin参数传入。
规则配置
来源访问控制规则( AuthorityRule )非常简单,要有以下配置项:
resource :
资源名,即限流规则的作用对象。limitApp :
对应的黑名单/白名单,不同origin用,分隔,如appA, appB。strategy :
限制模式。
默认为白名单模式。
实例:
比如我们希望控制对资源test的访问配置白名单,只有来源为appA 和appB的请求才可以通过,则可以配置如下的白名单
AuthorityRule rule = new AuthorityRule();
rule.setReosurce("test");
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
rule.setLimitApp("appA,appB");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
❓何为热点? 热点即经常访问的数据。
很多时候我们希望统计某个热点数据中访问频次最高的Top K数据,并对其访问进行限制。比如:
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Snetinel通过LRU策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控,热点参数限流支持集群模式
基本使用
要使用热点参数限流功能,需要引入以下的依赖文件
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-parameter-flow-controlartifactId>
dependency>
参数描述
Spring Cloud Alibaba默认为Sentinel整合了Servlet、RestTemplate、FeignClient和Spring WebFlux。它不仅补全了Hystrix在Servlet和RestTemplate这一块的空白,且还完全兼容了Hystrix在FeignClient中限流降级的用法,并支持灵活配置和调整流控规则。
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
server:
port: 8091
servlet:
context-path: "/"
spring:
cloud:
sentinel:
transport:
port: 8082 #跟控制台交流的端口,随意指定一个未使用的端口即可
dashboard: localhost:8080 # 指定控制台服务的地址
我们发现,使用Sentinel的时候,一旦我们重启过后Sentinel之前的配置就会全部没有,这是十分可怕的一件事,
那么,我们就可以使用我们之前学习过的Nacos的配置中心来实现Sentinel的配置持久化操做。
**注意:**要使用Nacos做持久化配置,就必须要修改Naocs的Application>properties里的配置信息,将其数据源修改为Spring.mysql,并将Nacos默认提供的数据文件导入Mysql数据库中
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
[
{
"resource":"Test",
"limitApp":"default",
"grade":1,
"count":2,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
}
]
Data Id: 和配置文件中的data_id相对应
Group: 和配置文件中的group_id相对应
配置内容:
与SphU.Entry或者SphO.Entry等哪五种定义资源的方式所声明的资源名对应
@RestController
public class TestController {
@GetMapping("/test")
@SentinelResource(value = "Test", blockHandler = "doPost")
public String Testhandler() {
return "你好啊,我是一个Test测试SpringBoot整合Sentinel" + System.currentTimeMillis();
}
public String doPost(BlockException exception) {
exception.printStackTrace();
return "系统繁忙,请稍后重试...";
}
}
server:
port: 8091
servlet:
context-path: "/"
spring:
cloud:
sentinel:
transport:
port: 8082 #跟控制台交流的端口,随意指定一个未使用的端口即可
dashboard: localhost:8080 # 指定控制台服务的地址
datasource:
ds:
nacos:
server-addr: 192.168.188.1:8848 # NACOS的连接地址
group-id: DEFAULT_GROUP # 组的id
data-id: Sentinel-Nacos # 数据源的dataID
rule-type: flow # 规则选用 流控规则
data-type: json # 配置的格式 json
这里我们可以观察发现其实Nacos做的持久化操作与之提供的数据库发现,我们一旦修改过Naocs的配置,就会在his_config_info里有记录,而config_info则是我们的使用的配置数据。
至此,我们对Sentinel的初步了解的差不多了,接下来就需要我平时多练习,来熟悉这个Sentinel使用