前面我们介绍了如何基于 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 的推送机制做到新规则的实时更新。

文章将持续更新,欢迎关注公众号:服务端技术精选。欢迎点赞、关注、转发