简介
Sentinel
是阿里开源的一款面向分布式、多语言异构化服务架构的流量治理组件。
主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性
核心概念
要想理解一个新的技术,那么首先你得理解它的一些核心概念
资源
资源是Sentinel
中一个非常重要的概念,资源就是Sentinel所保护的对象。
资源可以是一段代码,又或者是一个接口,Sentinel
中并没有什么强制规定,但是实际项目中一般以一个接口为一个资源,比如说一个http
接口,又或者是rpc
接口,它们就是资源,可以被保护。
资源是通过Sentinel
的API
定义的,每个资源都有一个对应的名称,比如对于一个http
接口资源来说,Sentinel
默认的资源名称就是请求路径。
规则
规则
也是一个重要的概念,规则其实比较好理解,比如说要对一个资源进行限流,那么限流的条件就是规则
,后面在限流的时候会基于这个规则
来判定是否需要限流。
Sentinel
的规则
分为流量控制规则
、熔断降级规则
以及系统保护规则
,不同的规则
实现的效果不一样。
入门Demo
测试代码
public static void testSentinel() {
//加载流控规则
initFlowRules();
for (int i = 0; i < 5; i++) {
Entry entry = null;
try {
entry = SphU.entry("sayHello");
//被保护的逻辑
log.info("访问sayHello资源");
} catch (BlockException ex) {
log.error("被流量控制了,可以进行降级处理");
} finally {
if (entry != null) {
entry.exit();
}
}
}
}
private static void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
//创建一个流控规则
FlowRule rule = new FlowRule();
//对sayHello这个资源限流
rule.setResource("sayHello");
//基于qps限流
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//qps最大为2,超过2就要被限流
rule.setCount(2);
rules.add(rule);
//设置规则
FlowRuleManager.loadRules(rules);
}
解释一下上面这段代码的意思
}
解释一下上面这段代码的意思
-
initFlowRules
:方法就是加载一个限流的规则,这个规则作用于sayHello这个资源,基于qps限流,当qps超过2之后就会触发限流。 -
SphU.entry("sayHello")
:这行代码是Sentinel最最核心的源码,这行代码表面看似风平浪静,实则暗流涌动。这行代码表明接下来需要访问某个资源(参数就是资源名称),会去检查需要被访问的资源是否达到设置的流控、熔断等规则。对于demo来说,就是检查sayHello这个资源是否达到了设置的流量控制规则。 -
catch BlockException
:也很重要,当抛出BlockException这个异常,说明触发了一些设置的保护规则,比如限流了,这里面就可以进行降级操作。 -
log.info("访问sayHello资源")
:这行代码表面是一个打印语句,实则就是前面一直在说的需要被保护的资源。
所以上面这段代码的整体意思就是对 sayHello这个需要访问的资源设置了一个流控规则,规则的内容是当qps到达2的时候触发限流,之后循环5次访问sayHello这个资源,在访问之前通过SphU.entry("sayHello")这行代码进行限流规则的检查,如果达到了限流的规则的条件,会抛出BlockException。
集成Spring
在实际的项目使用中一般不会直接写上面的那段demo代码,而是集成到Spring环境底下。
引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
Spring中资源规则
那么那前面提到的资源和对应的规则去哪了?
前面在说资源概念的时候,提到 Sentinel
中默认一个http接口就是一个资源,并且资源的名称就是接口的请求路径。而真正的原因是Sentinel
实现了SpringMVC
中的HandlerInterceptor
接口,在调用Controller
接口之前,会将一个调用接口设置为一个资源,代码如下
而getResourceName
方法就是获取资源名,其实就是接口的请求路径,比如前面提供的接口路径是/sayHello
,那么资源名就是/sayHello
。
再后面的代码就是调用上面demo中提到表面风平浪静,实则暗流涌动的SphU.entry(..)
方法,检查被调用的资源是否达到了设置的规则。
好了,既然资源默认是接口,已经有了,那么规则呢?
规则当然可以按照第一个demo的方式来做,比如在Controller接口中加载,代码如下。
@RestController
public class SentinelDemoController {
static {
List<FlowRule> rules = new ArrayList<>();
//创建一个流控规则
FlowRule rule = new FlowRule();
//对/sayHello这个资源限流
rule.setResource("/sayHello");
//基于qps限流
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//qps最大为2,超过2就要被限流
rule.setCount(2);
rules.add(rule);
//设置规则
FlowRuleManager.loadRules(rules);
}
@GetMapping("/sayHello")
public String sayHello() throws InterruptedException {
return "hello";
}
}
此时启动项目,在浏览器输入链接,疯狂快速使劲地多点几次,就出现下面这种情况
可以看出规则生效了,接口被Sentinel限流了,至于为什么出现这个提示,是因为Sentinel有默认的处理BlockException的机制,就在前面提到的进入资源的后面。
当然,也可以自定义处理的逻辑,实现
BlockExceptionHandler
接口就可以了。
Sentinel控制台
虽然上面这种硬编码规则的方式可以使用,但是在实际的项目中,肯定希望能够基于系统当期那运行的状态来动态调整规则,所以Sentinel提供了一个叫Dashboard应用的控制台,可以通过控制台来动态修改规则。
控制台其实就是一个jar包,可以从Sentinel的github仓库上下载。
之后通过java -jar命令启动就可以了,端口默认8080,浏览器访问 http://ip:8080/#/login就可以登录控制台了,用户名和密码默认都是 sentinel。
java -Dserver.port=8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar
那么问题来了:默认的用户名和密码在生产环境上肯定不能用,如何修改呢?
从 Sentinel 1.6.0 起 sentinel 已经支持自定义用户名和密码了,只需要在执行jar命令时指定即可,命令如下:
启动命令:
java -Dserver.port=8080
-Dcsp.sentinel.dashboard.server=localhost:8080
-Dproject.name=sentinel-dashboard
-Dsentinel.dashboard.auth.username=admin
-Dsentinel.dashboard.auth.password=123
-jar sentinel-dashboard-1.7.1.jar
用户可以通过如下参数进行配置:
-
-Dserver.port
:指定启动的端口,默认8080 -
-Dproject.name
:指定本服务的名称 -
-Dcsp.sentinel.dashboard.server
:指定sentinel控制台的地址,用于将自己注册进入实现监控自己 -
-Dsentinel.dashboard.auth.username=sentinel
用于指定控制台的登录用户名为 sentinel; -
-Dsentinel.dashboard.auth.password=123456
用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel; -
-Dserver.servlet.session.timeout=7200
用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;
此时服务要接入控制台,只需要在配置文件上加上控制台的ip和端口即可
spring:
cloud:
sentinel:
# 取消控制台懒加载
eager: true
transport:
# 指定控制台的ip和端口
dashboard: localhost:8080
项目刚启动的时候控制台默认是没有数据的,需要访问一下接口,之后就有了。
之后就可以看到/sayHello
这个资源,后面就可以通过页面设置规则。
防坑指南
新版的Sentinel只需要在VM启动参数的添加参数即可,不需要在属性文件里配置对应的地址,如图所示: