前言:
Sentinel干嘛用的,我们先通过几个问题点,再通过这个几个问题点来看Sentinel是干嘛用的。
限流:
限流,字眼上的意思就是限制流量(请求数等),就是打个比方:一桶水最多装50毫升以每秒不超过10毫升,就不会溢出,假设瞬间你的水龙头滴水量超过了10毫升,那桶就会溢出,可能比较慢,但是如果一秒20毫升的水滴入,那很快就溢出了。可能一瞬间,也可能慢慢叠加。
在系统上如果你的系统最大支持1000/qps,那如果一秒只有1000的qps进来,那服务器能稳定运行,如果一秒2000/qps的进来,服务器扛不住,扛不住就挂了,挂了没法提供对外服务导致业务直接熔断。如果算上1个请求的执行时间超过1秒,那可能不达到1000/qps也会扛不住。
限流的意义在于限制
如:服务器只有支撑1000QPS的处理能力,那就每秒放1000个请求,自然保证了服务器的稳定,这就是限流。
熔断降级:
在分布式系统中,如:一个下单接口,它调了一个接口,如时间太长未响应等问题,那肯定会拖垮核心服务,直接把当前这个服务给熔断掉。
由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断
附:ratelimter也可以用做限流,可自行研究
简述:
Sentinel主要限流、熔断降级,系统负载保护等多个维度来保障服务之间的稳定性
进入正文,接下来我们就以Springboot+sentinel来做一个限流的demo
一:创建springboot项目
这里只贴相关依赖和截图
1.1:基础代码
pom.xml
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<sentinel.version>1.8.0</sentinel.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sentinel -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!-- Sentinel注解 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!-- 控制台通信的jar包 客户端 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>${sentinel.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
1.2: properties
可自行修改成yml格式,我为了偷懒
server.port=8085
# 应用名称
spring.application.name=peng-sentinel
# Sentinel 控制台地址
spring.cloud.sentinel.transport.dashboard=localhost:8080
# 取消Sentinel控制台懒加载
# 默认情况下 Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包
# 配置 sentinel.eager=true 时,取消Sentinel控制台懒加载功能
spring.cloud.sentinel.eager=true
# 如果有多套网络,又无法正确获取本机IP,则需要使用下面的参数设置当前机器可被外部访问的IP地址,供admin控制台使用
# spring.cloud.sentinel.transport.client-ip=
1.3:Controller
@RestController
@RequestMapping("home")
public class HomeController {
@Autowired
private HomeService homeService;
@RequestMapping("/goHome")
@ResponseBody
public String queryHome(@RequestParam("homeName") String homeName) {
return homeService.queryHomeInfo(homeName);
}
}
1.4 service
1.4.1-- 硬编码限流
@Service
public class HomeService {
/**
* 订单查询接口, 使用Sentinel注解实现限流
*
* @param homeName
* @return
*/
@SentinelResource(value = "getHomeInfo", blockHandler = "handleFlowQpsException",
fallback = "queryHomeInfoFallback")
public String queryHomeInfo(String homeName) {
// 模拟接口运行时抛出代码异常
if ("000".equals(homeName)) {
throw new RuntimeException();
}
System.out.println("获取信息:" + homeName);
return "return Info :" + homeName;
}
/**
* 订单查询接口抛出限流或降级时的处理逻辑
*
* 注意: 方法参数、返回值要与原函数保持一致
* @return
*/
public String handleFlowQpsException(String homeName, BlockException e) {
e.printStackTrace();
System.out.println("FlowQpsException");
return "handleFlowQpsException for queryHomeInfo: " + homeName;
}
/**
* 订单查询接口运行时抛出的异常提供fallback处理
*
* 注意: 方法参数、返回值要与原函数保持一致
* @return
*/
public String queryHomeInfoFallback(String homeName, Throwable e) {
e.printStackTrace();
System.out.println("Fallback");
return "fallback queryHomeInfo: " + homeName;
}
// @PostConstruct
// public void initDegradeRule() {
// List<DegradeRule> rules = new ArrayList<>();
// DegradeRule rule = new DegradeRule();
// rule.setResource("getHomeInfo");
// // 80s内调用接口出现异常次数超过5的时候, 进行熔断
// rule.setCount(5);
// rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
// rule.setTimeWindow(80);
// rules.add(rule);
// DegradeRuleManager.loadRules(rules);
// }
@PostConstruct
public static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource("getHomeInfo");
// QPS控制在2以内
rule1.setCount(2);
// QPS限流
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
1.5:测试
1.5.1 测试硬编码
注意:测试前,先走标题二:引入sentinel服务端
启动项目
浏览器输入如下地址:http://localhost:8085/home/goHome?homeName=123
为了方便,我们引入客户端,我们已经引入了客户端的依赖,
我们还需要在idea插件添加一行命令
-Dproject.name=peng-sentinel -Dcsp.sentinel.dashboard.server=127.0.0.1:8080 -Dcsp.sentinel.api.port=8719
浏览器:http://localhost:8080/#/login
进入客户端
默认账号密码都是sentinel
注意,各个版本可能不一样
接下来我们连续访问
http://localhost:8085/home/goHome?homeName=123
就可以看到如下的信息
注意:根据官方wiki文档,sentinel控制台的实时监控数据,默认仅存储 5 分钟以内的数据。如需持久化,需要定制实现相关接口。持久化,后文会加入
1.5.2 控制台控制限流等
修改service
超过阈值就500拒绝掉了
暂时告一段落了,当然,控制台流控规则、降级规则、热点规则、系统规则等很多使用,可以参考官方文档,看看具体如何使用。
二:引入sentinel服务端
启动控制台
启动方式:
2.1:通过下载jar,命令方式
打开网站https://github.com/alibaba/Sentinel/releases,
然后下载对应版本的dashboard jar包,进入到该jar所在的目录,然后通过java命令运行该jar包
目前最新是1.8.1
一般下载都是第二新的
下载完成打开cmd窗口,
如windows系统,打开jar所在目录,在
然后输入cmd回车,即可cmd打开的窗口就在当前目录
输入如下命令
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject=peng-sentinel -jar sentinel-dashboard-1.8.0.jar
启动成功
2.2 下载源码进行打包
git clone 整个sentinel源码,进入sentinel-dashboard模块,执行打包命令:mvn clean package,生成一个可执行的 fat jar包,然后启动控制台,输入url:localhost:8080后即可进入主页面。