SpringCloud-整体学习(一)SpringCloud简介+版本选择
SpringCloud-整体学习(二)项目初始构建-加公共部分提取
SpringCloud-整体学习(三)Eureka、zookeeper、Consul(注册中心)
SpringCloud-整体学习(四)Ribbon(负载均衡+手写轮询算法)
SpringCloud-整体学习(五)OpenFeign(服务调用)
SpringCloud-整体学习(六)Hystrix(服务降级)
SpringCloud-整体学习(七)GateWay(服务网关)
SpringCloud-整体学习(八)Config、Bus、Stream(服务配置和消息交互)
SpringCloud-整体学习(九)Sleuth(分布式请求链路追踪)
SpringCloud-整体学习(十)SpringCloudAlibaba(注册中心+配置中心)
SpringCloud-整体学习(十一) Sentinel(服务降级)
SpringCloud-整体学习(十二) Seata(分布式事务)
git :
https://github.com/lucine-maker/cloud2020
gitee:
https://gitee.com/lucine_li_tao/springcloud
Sentinel文档地址:
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
Sentinel是什么
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
Sentinel下载安装运行
下载慢得多可以去码云上下载源码然后
mvn package -Dmaven.text.skip=true
https://gitee.com/mirrors/Sentinel/tree/1.7.0/
然后就拿到了jar
java -jar xxxx.jar
账号密码都是sentinel
Sentinel初始化监控
1、启动nacos --8848
2、新建cloudalibaba-sentinel-service8401
3、启动Sentinel8080
最后让8401注册进去nacos,然后在Sentinel保护启动的服务
2、新建:
pom
<dependencies>
<!-- SpringCloud ailibaba nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud ailibaba sentinel-datasource-nacos 持久化需要用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!-- SpringCloud ailibaba sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.lt.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
yml:
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinal-service
cloud:
nacos:
discovery:
#Nacos服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
# 默认8719端口,假如被占用了会自动从8719端口+1进行扫描,直到找到未被占用的 端口
port: 8719
management:
endpoints:
web:
exposure:
include: '*'
controller 和主启动都比较简单
第一次sentinel本身是懒加载只有请求一次后,就会加载进去
http://localhost:8401/testA
Sentinel流控-QPS直接失败
QPS 是每秒点击数
单机阈值数只要超过就报错。(快速失败情况下)
Sentinel流控-线程数直接失败
线程就不多解释了。
Sentinel流控-关联
b如果出了问题,A就限流自己(例如支付服务挂了,限流下订单的服务)
Sentinel流控-链路
https://www.it610.com/article/1294223962267525120.htm
这个文章中的链路流控讲的比较易懂写
Sentinel流控-预热
https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81—%E5%86%B7%E5%90%AF%E5%8A%A8
如果设置阈值为10,并不是上来就是10,而是慢慢的到达10。
默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
Sentinel流控-排队等待
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6-%E5%8C%80%E9%80%9F%E6%8E%92%E9%98%9F%E6%A8%A1%E5%BC%8F
Sentinel降级简介
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
Sentinel降级-RT
1、在未来的时间窗口(1s)中如果你200ms没有完成
2、在未来的时间窗口(1s)中线程数访问超过了设置的值(默认5),
一句话:一秒之内5个线程在200ms没有完成
1和2 都满足 就在后面所有的窗口期中都触发降级
Sentinel降级-异常比例、异常数
时间窗口期中,且请求线程数大于5:
成功次数/请求次数大于设置的比例就成功
异常数大于设置的值
Sentinel热点key(上)
https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
在controller中
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler ="deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value ="p2",required = false) String p2){
return "testHotKey 返回";
}
public String deal_testHotKey(String p1, String p2, BlockException e){
return "deal_testHotKey 返回";
}
@SentinelResource 注解中的value 为唯一标识资源名
blockHandler 为触发限流后触发的方法(不包括本身程序发生的错误)
sentinel中的参数索引 对方法入参的单个参数限制 是从0依次数
Sentinel热点key(下)
参数例外项可以让参数在特殊的值得时候不同的限流规则
写完记得点后面的添加。
上面是反例 :我的类型写错了,没有生效
Sentinel系统规则
https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
之前做的是单个方法的限制,这个是全局的系统的限制(调小了可能会导致整个系统不可用)
SentinelResource配置
新建Controller
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource")
public CommonResult testHotKey(){
return new CommonResult(200,"按资源名称限流测试ok",new Payment(2020L,"serial001"));
}
public CommonResult handleExcetion(BlockException e){
return new CommonResult(444,e.getClass().getCanonicalName()+"\t 服务不可用");
}
@GetMapping("/testMyhandler")
@SentinelResource(value = "testMyhandleraa",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler ="handleException2")
public CommonResult testMyhandler(){
return new CommonResult(200,"按资源名称限流测试ok",new Payment(2020L,"serial001"));
}
}
@GetMapping 和 @SentinelResource 中的值不要一致(否则可能会一直走自定义异常)
目前的问题和之前的Hystrix 面临的问题差不多需要解耦
新建CustomerBlockHandler(为异常做统一处理):
public class CustomerBlockHandler {
public static CommonResult handleException(BlockException exception){
return new CommonResult(4444,"自定义的异常4444----1");
}
public static CommonResult handleException2(BlockException exception){
return new CommonResult(4444,"自定义的异常4444----2");
}
}
Sentinel服务熔断Ribbon环境预说
搭建
9003和9004只是端口不一致
pom不在记录
yml
server:
port: 9004
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
management:
endpoints:
web:
exposure:
exclude: '*'
9003、4controller
@Value("${server.port}")
private String serverPort;
public static HashMap<Long, Payment> map = new HashMap<>();
static {
map.put(1L,new Payment(1L,"1111"));
map.put(2L,new Payment(2L,"2222"));
map.put(3L,new Payment(3L,"3333"));
}
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
Payment payment = map.get(id);
CommonResult<Payment> result = new CommonResult<>(200,"from mysql,serverPort: " + serverPort,payment);
return result;
}
84:
yml
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
# 默认8719端口,假如被占用了会自动从8719端口+1进行扫描,直到找到未被占用的 端口
port: 8719
#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
nacos-user-service: http://nacos-payment-provider
controller
@RequestMapping("/consumer/fallback/{id}")
// @SentinelResource(value = "fallback",fallback = "handlerFallback")
// @SentinelResource(value = "fallback",blockHandler = "blockHandler")
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
public CommonResult<Payment> fallback(@PathVariable Long id ){
CommonResult<Payment> result=restTemplate.getForObject(serverURL+"/paymentSQL/"+id,CommonResult.class,id);
if(id == 4){
throw new IllegalArgumentException("IllegalArgumentException ,非法参数异常");
}else if(result.getData() == null){
throw new NullPointerException("NullPointerException ,没有该条记录,空指针了");
}
return result;
}
public CommonResult handlerFallback(@PathVariable Long id,Throwable e){
Payment payment = new Payment(id,null);
return new CommonResult<>(444,"兜底的handlerFallback 触发"+e.getMessage(),payment);
}
public CommonResult blockHandler(@PathVariable Long id, BlockException e){
Payment payment = new Payment(id,null);
return new CommonResult<>(444,"blockHandler -sentinel 限流 触发"+e.getMessage(),payment);
}
主启动记得加@EnableDiscoveryClient
fallback 管运行异常
blockHandler管配置异常
目前配置
效果:
Sentinel服务熔断fallback和blockHandler配置
依次打开fallback 方法上面的注解并测试会发现
fallback 处理运行异常
blockHandler处理限流异常
如果同时触发 限流在前 异常在后
Sentinel服务熔断exceptionsToIgnore
添加的异常不进行fallback处理
Sentinel服务熔断OpenFeign
pom 中添加
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
yml
#激活sentinel对feign的支持
feign:
sentinel:
enabled: true
service
@Service
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService {
@GetMapping(value = "/paymentSQL/{id}")
CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
PaymentFallbackService就不写了实现PaymentService 接口并重写方法
controller中添加
@Resource
private PaymentService paymentService;
@GetMapping(value = "/consumer/openfeign/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable Long id){
return paymentService.paymentSQL(id);
}
启动类加@EnableFeignClients
就好了
坑:
启动报错:
问题:版本问题:
解决方案:
具体代码和理由和github说明:https://blog.csdn.net/pointer_v/article/details/104989935
Sentinel持久化规则
sentinel配置没有做持久化之前的配置会在重启后消失
pom
<!-- SpringCloud ailibaba sentinel-datasource-nacos 持久化需要用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
yml
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
nacos
[
{
"resource": "/byResource",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
},
{
"resource": "/testMyhandler",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]