Sentinel的流量管理是在控制器层面的(Controller)
原理是当收到请求时,先让请求经过配置文件中
spring.cloud.sentinel.transport.port设置的端口(每个项目必须唯一)
从Sentinel过一圈,再到自己的代码逻辑内运行,如流量过大,
按照限流规则,可能Sentinel会直接拦截请求,执行快速失败或其他,不再进入原来的代码里
请注意Sentinel本质上是一个运维工具,所以当项目重启后,原来设置的限流规则会被抛弃,需重新设置
需要下载Sentinel服务端程序,并运行jar包,启动命令(指定了端口为18080,默认8080)
java -jar sentinel-dashboard-1.8.2.jar --server.port=18080
出现以下界面表示启动成功.
可以访问http://localhost:18080进入控制台
账号密码皆为:sentinel
INFO: Sentinel log output type is: file
INFO: Sentinel log charset is: utf-8
INFO: Sentinel log base directory is: C:\Users\Administrator\logs\csp\
INFO: Sentinel log name use pid is: false
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.5.RELEASE)
2022-08-24 11:36:02.150 INFO 5660 --- [ main] c.a.c.s.dashboard.DashboardApplication : Starting DashboardApplication on DESKTOP-K8VRATH with PID 5660 (D:\sentinel\sentinel-dashboard-1.8.2.jar started by Administrator in D:\sentinel)
....................中间省略一堆....................
2022-08-24 11:36:03.808 INFO 5660 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Root mapping to handler of type [class org.springframework.web.servlet.mvc.ParameterizableViewController]
2022-08-24 11:36:03.818 INFO 5660 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-08-24 11:36:03.819 INFO 5660 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-08-24 11:36:03.942 INFO 5660 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2022-08-24 11:36:03.968 INFO 5660 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 18080 (http) with context path ''
2022-08-24 11:36:03.972 INFO 5660 --- [ main] c.a.c.s.dashboard.DashboardApplication : Started DashboardApplication in 2.034 seconds (JVM running for 2.321)
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
spring:
cloud:
sentinel:
transport:
dashboard: localhost:18080 #配置Sentinel仪表台的地址
port: 8721 #执行限流的端口号,每个项目必须唯一
添加依赖与配置项后,在控制器方法上,
添加**@SentinelResource(value = “XXX的方法”,blockHandler = “blockHandler”)**
value设置了此方法的名称
blockHandler指定了限流触发时的处理方法(可以不设置,异常会被抛出,具体参考异常拦截处理)
标注了这个注解的方法会被Sentinel进行管理
在控制器方法第一次运行后,可以在Sentinel仪表台界面中设置限流规则
如图所示,是设置QPS超过1的时候,触发限流
QPS: 每秒请求数
并发线程数: 同一时间调用此方法的线程数量,如设置1,则表示同一时间只有1个线程调用,第2个线程进来会被限流
@PostMapping("/reduceCount")
@ApiOperation("减少库存")
@SentinelResource(value = "减少库存的方法",blockHandler = "blockHandler")
public JsonResult<Void> reduceCount(StockReduceCountDTO stockReduceCountDTO) {
service.reduceCount(stockReduceCountDTO);
return JsonResult.ok();
}
//限流处理方法
public JsonResult<Void> blockHandler(StockReduceCountDTO stockReduceCountDTO, BlockException e){
log.debug("触发限流...");
JsonResult<Void> result = JsonResult.failed(ResponseCode.BAD_REQUEST, "服务器忙,请稍后再试!");
return result;
}
如未设置异常处理方法(blockHandler),将抛出java.lang.reflect.UndeclaredThrowableException异常
java.lang.reflect.UndeclaredThrowableException
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:770)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
..........省略一堆..........
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException
可在统一异常处理类中进行拦截处理
/**
* 处理限流后抛出的异常
*/
@ExceptionHandler({UndeclaredThrowableException.class})
public JsonResult<Void> handleUndeclaredThrowableException(UndeclaredThrowableException e) {
e.printStackTrace();
log.debug("请求被限流,直接返回数据");
JsonResult<Void> result = JsonResult.failed(ResponseCode.INTERNAL_SERVER_ERROR, "服务器忙,请稍后再试");
return result;
}
达内:lzy