在上一节中我们使用控制台简单实现了接口限流,这里的限流针对所有的MVC接口,但实际开发中,不仅需要对接口限流,也需要对某个方法的调用、某个外部资源的调用等都实现限流。这时候就需要手动定义限流的资源点,再另外配置限流策略。
本文将使用@SentinelResource注解灵活的定义资源点,同时讲解如何配置控制策略。
自定义资源点
第一步:新建模块alibaba-sentinel-reource,其中pom.xml和application.properties与alibaba-sentinel-rate-limiting一致
第二步:将SentinelResourceAspect注入Bean中,这个类就是对注解支持的配置Bean
package com.demo;import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;@SpringBootApplicationpublic class AlibabaSentinelResourceApplication {public static void main(String[] args) {SpringApplication.run(AlibabaSentinelResourceApplication.class, args);}@Beanpublic SentinelResourceAspect sentinelResourceAspect() {return new SentinelResourceAspect();}}
第三步:创建service类,同时加上@SentinelResource注解,用来标识这个方法需要控制流量
package com.demo;import com.alibaba.csp.sentinel.annotation.SentinelResource;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Service;@Slf4j@Servicepublic class EchoService {@SentinelResource(value = "EchoService#echo")public String echo(String str) {log.info(str);return str;}}
第四步:创建HTTP请求
package com.demo;import lombok.AllArgsConstructor;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.Date;@AllArgsConstructor@RestControllerpublic class EchoController {private final EchoService echoService;@GetMapping("echo")public String echo() {String str = echoService.echo("echo: " + new Date());log.info(str);return str;}}
实现限流与熔断降级
在定义资源点后,可以通过Sentinel控制台面板来设置限流规则与降级策略,同时通过@SentinelResource指定出现对应的异常处理策略。
限流控制
在Sentinel控制台对service进行流控,新增一个流控规则,如下图:

流控规则添加完成之后,通过Postman的Collection Runner发起多条请求,如下图:
可以看到一秒内发起了6次请求,前3次正常返回200 OK,而后3次请求出现了500错误,说明创建的流控规则已经生效,再看程序控制台,输出了如下日志:
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 causecom.alibaba.csp.sentinel.slots.block.flow.FlowException: null
限流的异常处理
默认情况下,Sentinel对控制资源的限流处理是抛出异常,显然这不够优雅。我们对程序做一些调整,根据实际业务针对限流做特殊处理。
比如修改EchoService:
package com.demo;import com.alibaba.csp.sentinel.annotation.SentinelResource;import com.alibaba.csp.sentinel.slots.block.BlockException;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Service;@Slf4j@Servicepublic class EchoService {@SentinelResource(value = "EchoService#echo", blockHandler = "echoBlockHandler")public String echo(String str) {return str;}public String echoBlockHandler(String str, BlockException ex) {log.error("echoBlockHandler: " + ex.getRuleLimitApp());return "block: " + str;}}
可以看到在原先的基础上,做了如下更改:
- 通过
@SentinelRsource的blockHandler属性指定具体的回调函数; - 实现
blockHandler回调函数,根据源码的注释说明,该方法的传参必须与资源点echo()的传参一样,并且最后加上BlockException异常参数;同时,返回类型也必须一样。
代码改好之后,重启应用。注意重启应用之后,Sentinel控制台需要重新添加流控规则。使用Postman访问接口,此时所有的接口都返回200 OK,不再返回异常信息,如下图:
同时控制台也会打印出我们定义的日志,如下:
2021-04-16 16:49:43.478 ERROR 23610 --- [nio-8004-exec-5] com.demo.EchoService : echoBlockHandler: default2021-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:
