SpringCloud 整合 Sentinel 实现服务自动熔断限流,实战讲解!
一、背景介绍
在上一篇文章中,我们介绍了 Spring Cloud Alibaba 技术体系中最核心的组件之一 Dubbo,它主要作用是通过简单的开发配置,即可实现服务之间的远程调用。与 OpenFegin 相比,Dubbo 远程通信效率更高,在国内很多的微服务项目中应用比较广泛。
今天通过这篇文章,并结合之前的知识,我们一起来了解一下 Spring Cloud Alibaba 技术体系中另一个最核心的组件之一 Sentinel。
二、Sentinel 简介
Sentinel 是一款面向分布式服务的流量治理组件,主要以流量为切入点,从流量控制、熔断降级、系统过载保护、热点流量防护等多个维度帮助开发者保障微服务的稳定性。
我们知道,目前互联网应用基本上都使用微服务框架来开发,一个对外的业务功能可能会涉及很长的服务调用链路,当某个服务出现异常时,如果没有一套系统保护机制,随着请求量的不断增大,可能会导致服务因资源耗产生更多的异常,进而发生雪崩现象。
因此设计一套系统保护机制,对微服务的稳定运行有着非常重要的意义。
在 Sentinel 出现之前,其实就已经有一套服务熔断降级组件,例如 Spring Cloud 中的 Hystrix 就是一款用于处理服务远程调用异常的熔断组件,当调用某个远程服务失败次数达到一个阀值,Hystrix 就会对某个服务自动开启熔断处理,当再次收到请求时,不再向远程服务发起调用,而转向本地指定的降级方法,避免系统资源的浪费。

Hystrix 作为第一代的微服务熔断降级组件,尽管已经足够出色,但是随着微服务的需求不断增多,Hystrix 也存在一些不足,最明显的就是支持的熔断降级维度较少,不够细粒,例如某个服务流量过大,需要对某个方法进行限流控制,还得定制化开发实现。
作为后起之秀,Sentinel 最大的亮点就是不仅支持对服务进行熔断降级处理,还支持对服务进行限流处理。
下面我们通过具体的例子,一起来看看如何使用 Sentinel 来实现服务限流和降级操作。
三、方案实践
3.1、快速开始
首先,创建一个 Java 项目,引入sentinel
核心包,示例如下。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.7.1</version>
</dependency>
创建一个 HelloSentinel
类,并设置相关的限流规则。
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
// 添加需要限流的规则
rule.setResource("hello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置当前服务QPS为5,也就是每秒最大请求次数为5次
rule.setCount(5);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
然后使用sentinel
中的SphU.entry()
和entry.exit()
方法,把需要流量控制的代码包围起来。示例如下:
public static void main(String[] args) throws Exception {
// 初始化限流规则
initFlowRules();
for (int i = 1; i < 10; i++) {
Entry entry = null;
try {
// 开启限流或者熔断保护,入参为上文设置的限流规则名称
entry = SphU.entry("hello");
// xxx业务逻辑 - 开始
System.out.println("第:" + i + "次执行,hello world");
// xxx业务逻辑 - 结束
} catch (BlockException e) {
// 业务请求太频繁,进行限流处理
System.out.println("第:" + i + "次执行,服务请求太频繁,进行限流处理!");
} catch (Exception e) {
// 业务发生异常,进行降级处理
Tracer.traceEntry(e, entry);
System.out.println("第:" + i + "次执行,服务请求发生异常,进行降级处理!");
} finally {
// 关闭资源
if (entry != null) {
entry.exit();
}
}
}
}
运行main
方法,执行结果如下:
第:1次执行,hello world
第:2次执行,hello world
第:3次执行,hello world
第:4次执行,hello world
第:5次执行,hello world
第:6次执行,服务请求太频繁,进行限流处理!
第:7次执行,服务请求太频繁,进行限流处理!
第:8次执行,服务请求太频繁,进行限流处理!
第:9次执行,服务请求太频繁,进行限流处理!
从运行结果上可以清晰的看到,当一段时间内请求次数超过5次,服务自动进行限流处理,如果发生异常也会进行降级处理。
通过以上的案例,相信大家对 Sentinel 已经有了初步的认识了。
3.2、SpringBoot 整合 Sentinel
下面我们再来看看另一个案例,如何在 SpringBoot 中利用 Sentinel 实现对服务的限流和降级操作。
实现步骤如下。
3.2.1、创建应用
首先,建一个 Maven 工程,命名为alibaba-sentinel-client
,并在pom.xml
中引入相关的依赖内容,示例如下:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencies>
<!-- SpringBoot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 服务限流和熔断处理:sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- 引入 springBoot 版本号 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 引入 spring cloud 版本号 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 引入 spring cloud alibaba 适配的版本号 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.2.2、添加限流规则
然后,创建一个接口,在需要进行流量控制的地方,用Sentinal
代码包裹起来,示例如下:
@RestController
public class SpcController {
@GetMapping("/hello")
public String hello() {
Entry entry = null;
try {
// 需要被保护的业务逻辑
entry = SphU.entry("hello");
// todo... 具体业务代码
} catch (BlockException e) {
// 资源访问阻止,被限流
return "请求太频繁了!";
} catch (Exception e) {
// 若需要配置降级规则,需要通过这种方式记录业务异常
Tracer.traceEntry(e, entry);
return "系统出现异常,请稍后重试!";
} finally {
// 务必保证 exit,务必保证每个 entry 与 exit 配对
if (entry != null) {
entry.exit();
}
}
return "hello,收到请求参数:" + name;
}
}
实际上还没写完,如同上文,还需要定义限流的规则,示例如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
//初始化限流规则
initFlowQpsRule();
}
private static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
// 添加需要限流的规则
FlowRule rule = new FlowRule();
rule.setResource("hello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置当前方法的请求规则,QPS最大值
rule.setCount(1);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
3.2.3、服务测试
最后,创建application.properties
全局配置文件。
spring.application.name=alibaba-sentinel-client
server.port=8002
将服务启动项目,访问http://127.0.0.1:8002/hell
,快速刷新几次,可以清晰的服务限流效果。

3.2.4、注解实现(推荐)
以上的实现方式,可能有些同学会说代码侵入性太强了,如果原有的系统要接入,需要改动的面积太大,有没有一种更加简洁的方式呢?
答案是肯定的!
try-catch-finally
代码,其实完全可以通过 Spring AOP 代理技术来实现。sentinel
内置了一个@SentinelResource
注解,可以利用它来实现目标方法的限流和降级操作,具体实现只需要一行代码,示例如下:
@RestController
public class HelloController {
@SentinelResource(value = "hello", blockHandler = "blockCallBack", fallback = "failCallBack")
@GetMapping("/hello")
public String hello(@RequestParam(value = "name", required = false) String name) {
if (StringUtils.isEmpty(name)) {
//抛出异常
throw new RuntimeException("name is null");
}
return "hello,收到请求参数:" + name;
}
/**
* 接受限流回调处理
* 注意:一定要跟原函数的返回值和形参一致,并且形参最后要加个BlockException参数,否则会报错,FlowException: null
* @param name
* @param ex
* @return
*/
public String blockCallBack(String name, BlockException ex) {
//打印异常
ex.printStackTrace();
return "【触发服务限流回调】接口请求太频繁了,请稍后再试!参数:" +name;
}
/**
* 接受熔断降级回调处理
* @param name
* @param ex
* @return
*/
public String failCallBack(String name, Throwable ex) {
//打印异常
ex.printStackTrace();
return "【触发服务降级回调】系统出现异常,请稍后重试!";
}
}
写完这段逻辑之后,还需要配置一个Sentinel
代理类,否则不生效。
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
最后启动项目,再次多次刷新接口,可以看到如下限流效果。

再次以一种错误的方式发起请求,可以看到如下降级效果。

3.2.5、支持对 OpenFeign 的适配
spring-cloud-starter-alibaba-sentinel
对 OpenFeign 也进行适配。如果想使用,除了引入必要的Starter
依赖包以外,还需要在配置文件打开 sentinel 对 feign 的支持,示例如下:
feign.sentinel.enabled=true
以下是一个 FeignClient 的简单使用示例:
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class)
public interface EchoService {
@GetMapping(value = "/hello/{name}")
String hello(@PathVariable("name") String name);
}
//必须交给spring 管理
@Component
class EchoServiceFallback implements EchoService {
@Override
public String hello(String name) {
return "服务自动降级...";
}
}
四、Sentinel 控制台
上面介绍的都是 Sentinel 的一些基本用法,实际上 Sentinel 还提供了一个更实用的功能,那就是它的服务监控平台。
下面我们一起来看看怎么使用它。
4.1、安装 Sentinel 控制台
首先下载控制台的 jar 包,当然你也可以通过下载源码进行编译。
// github下载页面地址
https://github.com/alibaba/Sentinel/releases
// github仓库地址
https://github.com/alibaba/Sentinel
// gitee仓库地址
https://gitee.com/mirrors/Sentinel
然后使用以下命令启动:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -jar sentinel-dashboard.jar
启动成功后,访问http://localhost:8080
,默认登录的用户名和密码都是sentinel
。
登录进去之后,可以看到类似如下主页面,有许多功能菜单,例如常用的簇点链路、流控规则、降级规则等。

4.2、客户端接入控制台
如何将上文中的应用接入到 Sentinel 控制台呢?请继续往下看。
首先,Sentinel 客户端如果想要接入控制台,需要引入Transport
模块来与Sentinel
控制台进行通信,示例如下:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
如果项目中已引入spring-cloud-starter-alibaba-sentinel
包,无需引入Transport
模块,因为这个包会自动将其一并引入进去。
然后,在application.properties
文件中,配置sentinel dashboard
的访问地址,示例如下:
spring.application.name=alibaba-sentinel-client
server.port=8002
# sentinel dashboard
spring.cloud.sentinel.transport.dashboard=localhost:8080
此时,可以移除Application
启动类中的initFlowQpsRule()
方法。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
// 移除初始化限流规则
// initFlowQpsRule();
}
}
最后,将服务启动,再次访问http://127.0.0.1:8002/hello
接口,点击簇点链路
菜单,可以在 Sentinel 控制台看到如下信息。

Sentinel 会将客户端中需要被保护的方法收集到监控台,点击资源名为hello
的流控
按钮,可以对当前资源设置限流规则。
例如,对hello
方法设置每秒的 QPS 超过 1,进行限流处理,具体操作如下:


再次访问客户端的http://127.0.0.1:8002/hello
接口,看看效果如何。

此外,还可以设置降级规则,例如对hello
方法设置 1 秒内异常数超过 2,进行降级处理。

除了流控规则、限流规则以外,Sentinel 还提供了热点规则、系统规则、授权规则等,在此就不做详细的介绍了,具体应用大家可以参阅官网文档。
五、小结
最后总结一下,本文主要围绕 Sentinel 作为服务限流和降级组件,在微服务中的应用方式进行了一次知识内容的总结。
与 Hystrix 相比,Sentinel 最大的亮点就是不仅支持对服务进行熔断降级处理,还支持对服务进行限流处理,颗粒度更细,实际的微服务项目开发中,应用比较广泛,因此掌握 Sentinel 应用技术,对我们项目的开发会有显著的帮助。
最后留下一个问题:如何将 Sentinel 规则数据进行持久化存储?下篇文章中,我们将揭晓答案!
六、参考
1、https://sca.aliyun.com/docs/2.2.x/user-guide/sentinel/overview
2、https://developer.aliyun.com/article/783342
3、https://sentinelguard.io/zh-cn/docs/introduction.html
作者:潘志的技术笔记
出处:https://pzblog.cn/
版权归作者所有,转载请注明出处
