前面我们介绍了如何基于 Sentinel 实现初步微服务限流,掌握了部署 Sentinel Dashboard与配置 Sentinel Core 客户端的技巧。了解了Sentinel 底层的细节与限流、熔断的各种配置方式。这篇文章,我们再来看几个Sentinel进阶的应用场景。
一、Sentinel 与 Nacos 整合实现规则持久化
在前面 Sentinel的使用过程中有这么一个现象:当微服务重启以后所有的配置规则都会丢失,主要原因是是默认微服务将 Sentinel 的规则保存在 JVM 内存中,当应用重启后 JVM 内存销毁,规则就会丢失。为了解决这个问题,我们就需要通过某种机制将配置好的规则进行持久化保存,同时这些规则变更后还能及时通知微服务进行变更。
针对这个问题,我们的Nacos在配置中心的用法和特性正好吻合。因此,Nacos也就成了Sentinel规则持久化的首选。下面我们通过实例来介绍一下实现方法:
1、构建工程
利用 Spring Initializr 向导创建 sentinel-sample 工程,pom.xml 增加以下三项依赖。
<!-- Nacos 客户端 Starter-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Sentinel 客户端 Starter-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 对外暴露 Spring Boot 监控指标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2、配置Nacos和Sentinel客户端
spring:
application:
name: sentinel-sample #应用名&微服务 id
cloud:
sentinel: #Sentinel Dashboard 通信地址
transport:
dashboard: 106.14.221.171:9100
eager: true #取消控制台懒加载
nacos: #Nacos 通信地址
server-addr: 106.14.221.171:8848
username: nacos
password: nacos
jackson:
default-property-inclusion: non_null
server:
port: 80
management:
endpoints:
web: #将所有可用的监控指标项对外暴露
exposure: #可以访问 /actuator/sentinel进行查看Sentinel监控项
include: '*'
logging:
level:
root: debug #开启 debug 是调试需要,生产改为 info 即可
3、添加接口类
在 sentinel-sample服务中,增加 SentinelSampleController 类,用于演示运行效果。
@RestController
public class SentinelSampleController {
//演示用的业务逻辑类
@Resource
private SampleService sampleService;
/**
* 流控测试接口
* @return
*/
@GetMapping("/test_flow_rule")
public ResponseObject testFlowRule(){
//code=0 代表服务器处理成功
return new ResponseObject("0","success!");
}
/**
* 熔断测试接口
* @return
*/
@GetMapping("/test_degrade_rule")
public ResponseObject testDegradeRule(){
try {
sampleService.createOrder();
}catch (IllegalStateException e){
//当 createOrder 业务处理过程中产生错误时会抛出IllegalStateException
//IllegalStateException 是 JAVA 内置状态异常,在项目开发时可以更换为自己项目的自定义异常
//出现错误后将异常封装为响应对象后JSON输出
return new ResponseObject(e.getClass().getSimpleName(),e.getMessage());
}
return new ResponseObject("0","order created!");
}
}
通过ResponseObject 封装响应对象:
/**
* 封装响应数据的对象
*/
public class ResponseObject {
private String code; //结果编码,0-固定代表处理成功
private String message;//响应消息
private Object data;//响应附加数据(可选)
public ResponseObject(String code, String message) {
this.code = code;
this.message = message;
}
//Getter/Setter省略
}
4、创建SampleService用于模拟业务逻辑
/**
* 演示用的业务逻辑类
*/
@Service
public class SampleService {
//模拟创建订单业务
public void createOrder(){
try {
//模拟处理业务逻辑需要101毫秒
Thread.sleep(101);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已创建");
}
}
5、启动服务
启动 sentinel-sample,访问localhost/test_flow_rule,浏览器出现code=0 的 JSON 响应,说明 sentinel-sample 服务启动成功。
{
code: "0",
message: "success!"
}
完成上述工作后,我们开始将Sentinel接入Nacos配置中心。
6、修改pom.xml
在pom.xml 新增 sentinel-datasource-nacos 依赖。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
sentinel-datasource-nacos 是 Sentinel 为 Nacos 扩展的数据源模块,允许将规则数据存储在 Nacos 配置中心,在微服务启动时利用该模块 Sentinel 会自动在 Nacos下载对应的规则数据。
7、修改application.yml配置
在application.yml 文件中增加 Nacos下载规则,在原有的sentinel 配置下新增 datasource 选项。
spring:
application:
name: sentinel-sample #应用名&微服务id
cloud:
sentinel: #Sentinel Dashboard通信地址
transport:
dashboard: 106.14.221.171:9100
eager: true #取消控制台懒加载
datasource:
flow: #数据源名称,可以自定义
nacos: #nacos配置中心
#Nacos内置配置中心,因此重用即可
server-addr: ${spring.cloud.nacos.server-addr}
dataId: ${spring.application.name}-flow-rules #定义流控规则data-id,完整名称为:sentinel-sample-flow-rules,在配置中心设置时data-id必须对应。
groupId: SAMPLE_GROUP #gourpId对应配置文件分组,对应配置中心groups项
rule-type: flow #flow固定写死,说明这个配置是流控规则
username: nacos #nacos通信的用户名与密码
password: nacos
nacos: #Nacos通信地址
server-addr: 106.14.221.171:8848
username: nacos
password: nacos
...
通过这一份配置,微服务在启动时就会自动从 Nacos 配置中心 SAMPLE_GROUP 分组下载 data-id 为 sentinel-sample-flow-rules 的配置信息并将其作为流控规则生效。
8、在Nacos中新增配置项
在 Nacos 配置中心页面,新增 data-id 为sentinel-sample-flow-rules 的配置项。
配置完成后,我们启动服务来验证一下: 访问 localhost/test_flow_rule,在日志中将会看到这条 Debug 信息,说明在服务启动时已向 Nacos 配置中心获取到流控规则。
DEBUG 12728 --- [main] s.n.www.protocol.http.HttpURLConnection : sun.net.www.MessageHeader@5432948015 pairs: {GET /nacos/v1/cs/configs?dataId=sentinel-sample-flow-rules&accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYxMDg3NTA1M30.Hq561OkXuAqPI20IBsnPIn0ia86R9sZgdWwa_K8zwvw&group=SAMPLE_GROUP HTTP/1.1: null}...
在浏览器反复刷新,当 test_flow_rule 接口每秒超过 2 次访问,就会出现“Blocked by Sentinel (flow limiting)”的错误信息,说明流控规则已生效。
二、熔断保护自定义资源点
我们已经实现了 test_flow_rule 接口的流控规则,在前面的文章中我们都是针对 RESTful 的接口进行限流熔断设置,但是在项目中有的时候是要针对某一个 Service 业务逻辑方法进行限流熔断等规则设置,这要怎么办呢?
在 sentinel-core 客户端中为开发者提供了 @SentinelResource 注解,该注解允许在程序代码中自定义 Sentinel 资源点来实现对特定方法的保护,下面我们以熔断降级规则为例来聊聊。
熔断降级是指在某个服务接口在执行过程中频繁出现故障的情况下,在一段时间内将服务停用的保护措施。在 sentinel-core 中基于 **Spring AOP(面向切面技术)**可在目标 Service 方法执行前按熔断规则进行检查,只允许有效的数据被送入目标方法进行处理。
以 sentinel-sample 工程为例,我们希望对 SampleSerivce.createOrder方法进行熔断保护,该如何设置呢?
1、申明切面类
在应用入口 SentinelSampleApplication声明 SentinelResourceAspect,SentinelResourceAspect就是 Sentinel 提供的切面类,用于进行熔断的前置检查。
@SpringBootApplication
public class SentinelSampleApplication {
// 注解支持的配置Bean
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
public static void main(String[] args) {
SpringApplication.run(SentinelSampleApplication.class, args);
}
}
2、申明资源点
在 SampleService.createOrder 方法上增加 @SentinelResource 注解用于声明 Sentinel 资源点,只有声明了资源点,Sentinel 才能实施限流熔断等保护措施。
/**
* 演示用的业务逻辑类
*/
@Service
public class SampleService {
//资源点名称为createOrder
@SentinelResource("createOrder")
/**
* 模拟创建订单业务
* 抛出IllegalStateException异常用于模拟业务逻辑执行失败的情况
*/
public void createOrder() throws IllegalStateException{
try {
//模拟处理业务逻辑需要101毫秒
Thread.sleep(101);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已创建");
}
}
修改完毕,启动服务访问 localhost/test_degrade_rule,当见到 code=0 的JSON 响应便代表应用运行正常。
{
code: "0",
message: "order created!"
}
打开访问 Sentinel Dashboard,在簇点链路中要确认 createOrder资源点已存在。
3、获取熔断规则
打开sentinel-sample 工程的 application.yml 文件,将服务接入 Nacos 配置中心的参数以获取熔断规则。
datasource:
flow: #之前的流控规则,直接忽略
...
degrade: #熔断规则
nacos:
server-addr: ${spring.cloud.nacos.server-addr}
dataId: ${spring.application.name}-degrade-rules
groupId: SAMPLE_GROUP
rule-type: degrade #代表熔断
username: nacos
password: nacos
熔断规则的获取过程和前面流控规则类似,只不过 data-id 改为sentinel-sample-degrade-rules,以及 rule-type 更改为 degrade。
4、在Nacos中配置熔断规则
设置 data-id 为 sentinel-sample-degrade-rules,Groups 为 SAMPLE_GROUP与微服务的设置保持一致。
5、规则验证
因为规则允许最大时长为 100 毫秒,而在 createOrder 方法中模拟业务处理需要 101 毫秒,显然会触发熔断。
@SentinelResource("createOrder")
//模拟创建订单业务
public void createOrder(){
try {
//模拟处理业务逻辑需要101毫秒
Thread.sleep(101);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已创建");
}
连续访问 localhost/test_degrade_rule,当第二次访问时便会出现 500 错误。
在控制台日志也看到了 ERROR 日志,说明熔断已生效。
2021-01-17 17:19:44.795 ERROR 13244 --- [p-nio-80-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause
com.alibaba.csp.sentinel.slots.block.degrade.DegradeException: null
看到 DegradeException 就说明之前配置的熔断规则已经生效。
看到这里,我们已经将 Sentinel 规则在 Nacos配置中心进行了持久化,并通过 Nacos 的推送机制做到新规则的实时更新。
文章将持续更新,欢迎关注公众号:服务端技术精选。欢迎点赞、关注、转发。