Sentinel入门
前言
Sentinel 是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 的历史
- 2012 年,Sentinel 诞生,主要功能为入口流量控制。
- 2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
- 2018 年,Sentinel 开源,并持续演进。
- 2019 年,Sentinel 朝着多语言扩展的方向不断探索,推出 C++ 原生版本,同时针对 Service Mesh 场景也推出了 Envoy 集群流量控制支持,以解决 Service Mesh 架构下多语言限流的问题。
- 2020 年,推出 Sentinel Go 版本,继续朝着云原生方向演进。
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
![Sentinel入门](https://img.it610.com/image/info10/b395d4b1554b4dcb9436fd6c09cc2bc2.jpg)
文章图片
图片.png Sentinel 的开源生态
![Sentinel入门](https://img.it610.com/image/info10/4919e41af4e34d8f82014cd81263572b.jpg)
文章图片
图片.png Sentinel 分为两个部分
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
com.alibaba.csp
sentinel-core
1.7.1
注意: 从 Sentinel 1.5.0 开始仅支持 JDK 1.7 或者以上版本。Sentinel 1.5.0 之前的版本最低支持 JDK 1.6。2.定义资源 接下来,我们把需要控制流量的代码用 Sentinel API SphU.entry("HelloWorld") 和 entry.exit() 包围起来即可。
public static void main(String[] args) {
// 配置规则.
initFlowRules();
while (true) {
Entry entry = null;
try {
entry = SphU.entry("HelloWorld");
/*您的业务逻辑 - 开始*/
System.out.println("hello world");
/*您的业务逻辑 - 结束*/
} catch (BlockException e1) {
/*流控逻辑处理 - 开始*/
System.out.println("block!");
/*流控逻辑处理 - 结束*/
} finally {
if (entry != null) {
entry.exit();
}
}
}
}
3.定义规则
接下来,通过规则来指定允许该资源通过的请求次数,例如下面的代码定义了资源 HelloWorld 每秒最多只能通过 20 个请求。
private static void initFlowRules(){
List rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("HelloWorld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20.
rule.setCount(20);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
注解支持 Sentinel 提供了
@SentinelResource
注解用于定义资源,并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException
等。使用 Sentinel Annotation AspectJ Extension 的时候需要引入以下依赖:
com.alibaba.csp
sentinel-annotation-aspectj
x.y.z
将 SentinelResourceAspect 注册为一个 Spring Bean
@Configuration
public class SentinelAspectConfiguration {@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
示例代码
public class TestService {// 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 static 函数.
@SentinelResource(value = "https://www.it610.com/article/test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
public void test() {
System.out.println("Test");
}// 原函数
@SentinelResource(value = "https://www.it610.com/article/hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
public String hello(long s) {
return String.format("Hello at %d", s);
}// Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
public String helloFallback(long s) {
return String.format("Halooooo %d", s);
}// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String exceptionHandler(long s, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
}
代码实战 新建一个SpringBoot的项目
1.pom依赖
4.0.0 org.springframework.boot
spring-boot-starter-parent
2.2.1.RELEASE
com.example.sentinel
sentinel-demo
0.0.1-SNAPSHOT
sentinel-demo
sentinel demo 1.8
2.2.1.RELEASE
1.7.0
org.springframework.boot
spring-boot-starter
${spring.boot.version}
org.springframework.boot
spring-boot-starter-web
${spring.boot.version}
org.springframework.boot
spring-boot-starter-aop
${spring.boot.version}
org.projectlombok
lombok
true
com.alibaba.csp
sentinel-core
${sentinel.version}
com.alibaba.csp
sentinel-annotation-aspectj
${sentinel.version}
com.alibaba.csp
sentinel-transport-simple-http
${sentinel.version}
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-maven-plugin
2.Controller
package com.example.sentinel.sentineldemo.controller;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.sentinel.sentineldemo.service.TestSentinelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @Author: Monday
* @Date: 2020/4/1 0001 上午 11:44
* @Description:
*/
@Controller
@RequestMapping("test")
public class TestSentinelController {private static final String KEY = "queryOne";
@Autowired
private TestSentinelService testSentinelService;
/**
* 代码不加任何限流 熔断
*
* @return
*/
@RequestMapping("/getValue_0")
@ResponseBody
@SentinelResource("queryZero")
public String getValue_0(@RequestParam("key") String key) {
return testSentinelService.getValue_0(key);
}/**
* 限流实现方式一: 抛出异常的方式定义资源
*
* @param key
* @return
*/
@RequestMapping("/getValue_1")
@ResponseBody
public String getValue_1(@RequestParam("key") String key) {
Entry entry = null;
// 资源名
String resourceName = KEY;
try {
// entry可以理解成入口登记
entry = SphU.entry(resourceName);
// 被保护的逻辑, 这里为查询接口
return testSentinelService.getValue_1(key);
} catch (BlockException blockException) {
// 接口被限流的时候, 会进入到这里
return "接口限流, 返回空";
} finally {
// SphU.entry(xxx) 需要与 entry.exit() 成对出现,否则会导致调用链记录异常
if (entry != null) {
entry.exit();
}
}
}/**
* 限流实现方式二: 注解定义资源
*
* @param key
* @return
*/
@RequestMapping("/getValue_2")
@ResponseBody
public String getValue_2(@RequestParam("key") String key) {
String res = testSentinelService.getValue_2(key);
return res;
}}
3.Service
package com.example.sentinel.sentineldemo.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: Monday
* @Date: 2020/4/1 0001 上午 11:45
* @Description: 商品查询接口
*/
@Component
@Slf4j
public class TestSentinelService {private static final String KEY = "queryTwo";
/**
* 代码不加任何限流 熔断
*
* @param key
* @return
*/
public String getValue_0(String key) {
System.out.println("获取Value:" + key);
return "return value :" + key;
}/**
* 抛出异常的方式定义资源
*
* @param key
* @return
*/
public String getValue_1(String key) {
System.out.println("获取Value:" + key);
return "return value :" + key;
}/**
* 注解定义资源
*
* @param key
* @return
*/
@SentinelResource(value = https://www.it610.com/article/KEY, blockHandler ="blockHandlerMethod", fallback = "queryFallback")
public String getValue_2(String key) {
// 模拟调用服务出现异常
if ("0".equals(key)) {
throw new RuntimeException();
}
return "query value success, " + key;
}public String blockHandlerMethod(String key, BlockException e) {
return "queryValue error, blockHandlerMethod res: " + key;
}public String queryFallback(String key, Throwable e) {
return "queryValue error, return fallback res: " + key;
}/**
* 初始化限流配置
*/
@PostConstruct
public void initDegradeRule() {
List rules = new ArrayList();
FlowRule rule1 = new FlowRule();
rule1.setResource(KEY);
// QPS控制在2以内
rule1.setCount(2);
// QPS限流
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
}
4.控制台
4.1下载 从 release 页面 下载截止目前为止最新版本的控制台 jar 包
![Sentinel入门](https://img.it610.com/image/info10/11efc7959c45473fb737c58a336fa04b.png)
文章图片
图片.png
注意:用户可以通过如下参数进行配置
启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本
从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的 登录 功能,默认用户名和密码都是 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 分钟
java -jar sentinel-dashboard-1.7.1.jar
访问http://localhost:8080
![Sentinel入门](https://img.it610.com/image/info10/1f82c34071a24e37b69951d2d5edad82.jpg)
文章图片
图片.png
4.3登录
![Sentinel入门](https://img.it610.com/image/info10/0c4f9036fea240228c0390562d44cf2d.jpg)
文章图片
图片.png
可以看到当前控制台中没有任何的应用,因为还没有应用接入。
5.客户端接入
启动了控制台模块后,控制台页面都是空的,需要接入客户端。
5.1导入与控制台通信的jar包
com.alibaba.csp
sentinel-transport-simple-http
${sentinel.version}
5.2 配置应用启动参数 引入了依赖之后,接着就是在我们的应用中配置 JVM 启动参数,如下所示:
-Dproject.name=xxx -Dcsp.sentinel.dashboard.server=consoleIp:port
其中的consoleIp和port对应的就是我们部署的 sentinel dashboard 的ip和port,我这里对应的是 127.0.0.1 和 8080,按照实际情况来配置 dashboard 的ip和port就好了,如下图所示:
![Sentinel入门](https://img.it610.com/image/info10/96828165f5d547669747c51fdd62a90f.jpg)
文章图片
图片.png 5.3 启动应用 启动上边的springboot项目
5.4 测试效果 本demo中http://localhost:8083/test/getValue_2?key=kobe接口执行多次,会触发限流操作,这时候再去看控制台:
![Sentinel入门](https://img.it610.com/image/info10/81e7261e258d4d60b55844c9e293757c.jpg)
文章图片
图片.png 【Sentinel入门】
![Sentinel入门](https://img.it610.com/image/info10/6a9116f1de1c4fe2b6343aa83181f304.jpg)
文章图片
图片.png
![Sentinel入门](https://img.it610.com/image/info10/657f2501c7b041c7bdf45254f233a202.jpg)
文章图片
图片.png
推荐阅读
- 由浅入深理解AOP
- android|android studio中ndk的使用
- 斐讯K2|斐讯K2 固件搜集
- typeScript入门基础介绍
- 植物能治病的奥秘——植物精气
- 11-代码注入
- linux定时任务contab
- neo4j|neo4j cql语句 快速查询手册
- 构建App(一)(框架与结构)
- Android|Android sqlite3数据库入门系列