在上一节中我们使用控制台简单实现了接口限流,这里的限流针对所有的MVC接口,但实际开发中,不仅需要对接口限流,也需要对某个方法的调用、某个外部资源的调用等都实现限流。这时候就需要手动定义限流的资源点,再另外配置限流策略。
本文将使用@SentinelResource注解灵活的定义资源点,同时讲解如何配置控制策略。

自定义资源点

第一步:新建模块alibaba-sentinel-reource,其中pom.xmlapplication.propertiesalibaba-sentinel-rate-limiting一致
第二步:SentinelResourceAspect注入Bean中,这个类就是对注解支持的配置Bean

  1. package com.demo;
  2. import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.context.annotation.Bean;
  6. @SpringBootApplication
  7. public class AlibabaSentinelResourceApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(AlibabaSentinelResourceApplication.class, args);
  10. }
  11. @Bean
  12. public SentinelResourceAspect sentinelResourceAspect() {
  13. return new SentinelResourceAspect();
  14. }
  15. }

第三步:创建service类,同时加上@SentinelResource注解,用来标识这个方法需要控制流量

  1. package com.demo;
  2. import com.alibaba.csp.sentinel.annotation.SentinelResource;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.stereotype.Service;
  5. @Slf4j
  6. @Service
  7. public class EchoService {
  8. @SentinelResource(value = "EchoService#echo")
  9. public String echo(String str) {
  10. log.info(str);
  11. return str;
  12. }
  13. }

第四步:创建HTTP请求

  1. package com.demo;
  2. import lombok.AllArgsConstructor;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RestController;
  5. import java.util.Date;
  6. @AllArgsConstructor
  7. @RestController
  8. public class EchoController {
  9. private final EchoService echoService;
  10. @GetMapping("echo")
  11. public String echo() {
  12. String str = echoService.echo("echo: " + new Date());
  13. log.info(str);
  14. return str;
  15. }
  16. }

实现限流与熔断降级

在定义资源点后,可以通过Sentinel控制台面板来设置限流规则与降级策略,同时通过@SentinelResource指定出现对应的异常处理策略。

限流控制

在Sentinel控制台对service进行流控,新增一个流控规则,如下图:
image.png
image.png
流控规则添加完成之后,通过Postman的Collection Runner发起多条请求,如下图:
image.png
可以看到一秒内发起了6次请求,前3次正常返回200 OK,而后3次请求出现了500错误,说明创建的流控规则已经生效,再看程序控制台,输出了如下日志:

  1. 2021-04-16 08:53:45.394 ERROR 22510 --- [io-8004-exec-10] 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
  2. com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

限流的异常处理

默认情况下,Sentinel对控制资源的限流处理是抛出异常,显然这不够优雅。我们对程序做一些调整,根据实际业务针对限流做特殊处理。
比如修改EchoService

  1. package com.demo;
  2. import com.alibaba.csp.sentinel.annotation.SentinelResource;
  3. import com.alibaba.csp.sentinel.slots.block.BlockException;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.stereotype.Service;
  6. @Slf4j
  7. @Service
  8. public class EchoService {
  9. @SentinelResource(value = "EchoService#echo", blockHandler = "echoBlockHandler")
  10. public String echo(String str) {
  11. return str;
  12. }
  13. public String echoBlockHandler(String str, BlockException ex) {
  14. log.error("echoBlockHandler: " + ex.getRuleLimitApp());
  15. return "block: " + str;
  16. }
  17. }

可以看到在原先的基础上,做了如下更改:

  • 通过@SentinelRsourceblockHandler属性指定具体的回调函数;
  • 实现blockHandler回调函数,根据源码的注释说明,该方法的传参必须与资源点echo()的传参一样,并且最后加上BlockException异常参数;同时,返回类型也必须一样。

代码改好之后,重启应用。注意重启应用之后,Sentinel控制台需要重新添加流控规则。使用Postman访问接口,此时所有的接口都返回200 OK,不再返回异常信息,如下图:
image.png
同时控制台也会打印出我们定义的日志,如下:

  1. 2021-04-16 16:49:43.478 ERROR 23610 --- [nio-8004-exec-5] com.demo.EchoService : echoBlockHandler: default
  2. 2021-04-16 16:49:43.478 INFO 23610 --- [nio-8004-exec-5] com.demo.EchoController : block: echo: Fri Apr 16 16:49:43 CST 2021

代码示例

  • Github:
  • Gitee: