视频链接:2020最新版SpringCloud框架开发教程-周阳
文章源码:https://github.com/geyiwei-suzhou/cloud2020/
如何使用官网有详细的教程:如何使用,这里就不再搬运了,只记录一些配置步骤
流控规则
新增如下流控:表示1秒内查询1次正常,若超过1次,就快速失败,报默认错误
当一秒内多次访问/testA
接口,将会返回错误信息:Blocked by Sentinel (flow limiting)
由com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController抛出
QPS vs 线程数
直接 vs 关联 vs 链路:关联 -> 当与A关联的资源B达到阈值后,就限流A自己
快速失败 vs Warm Up vs 排队等待:Warm Up -> 阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值,由类com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController处理 排队等待 -> 匀速排队,让请求以均匀的速度通过,阈值类型必须设成QPS,否则无效,由类com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController处理
降级规则
新增如下降级:
要求QPS大于5
,默认行为是抛出DegradeException,Sentinel的断路器没有半开状态
RT(平均响应时间) vs 异常比例 vs 异常数
异常数 -> 时间窗口必须大于60s
热点规则key
由com.alibaba.csp.sentinel.slots.block.BlockException处理
自定义降级方法
Hystrix | Sentinel |
---|---|
@HystrixCommand | @SentinelResource |
在com.antherd.springcloud.alibaba.controller.FlowLimitController类中新增方法:
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "dealTestHotKey") // value:sentinel热点key资源名,blockHandler不会处理RuntimeException异常
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "***** testHotKey";
}
public String dealTestHotKey(String p1, String p2, BlockException exception) {
return "***** dealTestHotKey o(╥﹏╥)o"; // sentinel 系统默认的提示:Blocked by Sentinel (flow limiting)
}
调用包含第一个参数的次数超过阈值就使用兜底方法,如果不添加兜底方法,则超过阈值时返回500错误页面
期望第一个参数当它是某个特殊值时,它的限流值和平时不一样,如:调用第一个参数值为5时,限流阈值为100
系统自适应限流
系统自适应从整体维度对应用入口流量进行控制
阈值类型
- Load自适应
- CPU usage
- 平均RT
- 并发线程数
- 入口QPS
SentinelResource 配置
注解方式埋点不支持private方法
Sentinel主要有三个核心Api:SphU定义资源、Tacer定义统计、ContextUtil定义了上下文
新建类:com.antherd.springcloud.alibaba.controller.RateLimitController
package com.antherd.springcloud.alibaba.controller;
import cn.hutool.http.HttpStatus;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.antherd.springcloud.entities.CommonResult;
import com.antherd.springcloud.entities.Payment;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@EnableDiscoveryClient
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(HttpStatus.HTTP_OK, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
}
public CommonResult handleException(BlockException exception) {
return new CommonResult(444, exception.getClass().getCanonicalName());
}
}
新增流控规则(按照资源名称)
上述配置都是临时配置,服务停止后配置丢失
在类com.antherd.springcloud.alibaba.controller.RateLimitController中新增方法
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl() {
return new CommonResult(HttpStatus.HTTP_OK, "按url限流测试OK", new Payment(2020L, "serial002"));
}
新增流控规则(按照URL)
限流后返回:Blocked by Sentinel (flow limiting)
上面配置面临的问题:
- 系统默认的,没有体现我们自己的业务要求
- 依照现有条件,我们自定义的处理方法和业务代码耦合在一起,不直观
- 每个业务方法都添加一个兜底方法,代码膨胀加剧
- 全局统一处理方法没有体现
新建类:com.antherd.springcloud.alibaba.handler.CustomerBlockHandler类用于自定义
限流处理逻辑
package com.antherd.springcloud.alibaba.handler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.antherd.springcloud.entities.CommonResult;
import com.antherd.springcloud.entities.Payment;
public class CustomerBlockHandler {
public static CommonResult handlerException(BlockException exception) {
return new CommonResult(200, "按客户自定义, global handler exception-----1", new Payment(2020L, "serial003"));
}
public static CommonResult handlerException2(BlockException exception) {
return new CommonResult(200, "按客户自定义, global handler exception-----2", new Payment(2020L, "serial003"));
}
}
在类com.antherd.springcloud.alibaba.controller.RateLimitController中新增方法
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler() {
return new CommonResult(HttpStatus.HTTP_OK, "按客户自定义", new Payment(2020L, "serial003"));
}