一个强大的流控制组件,可实现微服务的可靠性,弹性和监视。
Sentinel以“流”为切入点,并在流控制, 流量整形,电路中断和系统自适应保护等多个领域工作,以确保微服务的可靠性和弹性。
Sentinel具有以下功能:
丰富的适用场景
实时监控
广泛的开源生态系统
多种语言支持
官网:https://github.com/alibaba/Sentinel
下载:https://github.com/alibaba/Sentinel/releases
怎么玩:服务雪崩、服务降级、服务熔断、服务限流
sentinel分为两个部分:
核心库:不依赖任何框架/库,能够运行于所有java运行时环境,同时对Dubbo/Spring Cloud等框架也有较好的支持。
控制台(Dashboard):基于springboot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。
安装步骤:
本次下载sentinel-dashboard-1.7.0.jar这个版本
运行命令,到sentinel的所在目录下:java -jar sentinel-dashboard-1.7.0.jar
访问sentinel管理界面:http://localhost:8080/#/login,账号密码均为sentinel
(1)先启动Nacos注册中心
(2)创建Maven工程作为服务提供者(cloudalibab-sentinel-service8401)
(3)添加Nacos和Sentinel依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
(4)application.yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos服务注册中心地址
sentinel:
transport:
dashboard: localhost:8080 #配置sentinel 控制台(dashboard)地址,使8080监控8401
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
management: #暴露监控的端点
endpoints:
web:
exposure:
include: '*'
(5)Controller
@RestController
public class FlowLimitController
{
@GetMapping("/testA")
public String testA() throws InterruptedException {
return "------testA";
}
@GetMapping("/testB")
public String testB() {
return "------testB";
}
}
(5)启动类上加@EnableDiscoveryClient
(6)测试:
启动Sentinel控制台、启动8401、查看sentinel控制台
一打开是空的,因为Sentinel采用的懒加载说明,访问一次Controller即可。
1.直接(默认):快速失败报默认错误:Blocked by Sentinel(flow limiting)
问题:直接调用默认报错信息,是否应该有我们自己的后续处理?类似fallback的兜底方法?
2.关联:当与A关联的资源B达到阈值后,就限流A
3.链路:多个请求调用了同一个微服务
1.快速失败(默认)
2.预热(Warm UP)
应用场景如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,慢慢的把流量放进来,慢慢的把阈值恢复到原来设置的阈值
3.排队等待
Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。
Sentinel的断路器是没有半开状态的:半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。
1.RT:当1秒内持续进入5或大于5个请求,平均响应时间(秒)均超过阈值(ms),在接下来的时间窗口(s)之内,对这个方法的调用都会自动地熔断(抛出DegradeException)
Sentinel默认统计的RT上限是4900ms,超过此阈值都会算作4900ms,要更改的话配置:Dcsp.sentinel.statistic.max.rt=xxx
2.异常比例:当1秒内进入请求>=5,并且异常比例超过阈值之后,资源进入降级状态。不满足1秒内请求>5条件的话,还是会照常报错
3.异常数:当资源1分钟的异常数目超过阈值之后会进行熔断。由于统计窗口是分钟级别的,若小于60秒,则结束熔断状态仍可能再进入熔断状态。所以时间窗口一定大于等于60秒
使用@SentinelResource(value="要在sentinel上配置热点规则的资源名")
注意:@SentinelResource处理的是控制台配置的违规情况,运行出错该走异常就走异常
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey") //违背了热点key规则,就找兜底的方法,不配置blockHandler就报异常
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2) {
//int age = 10/0;
return "------testHotKey";
}
//兜底方法
public String deal_testHotKey (String p1, String p2, BlockException exception){
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel默认的提示是:Blocked by Sentinel(flow limiting)
}
根据配置的限流阈值与模式,对包含该参数的资源调用进行限流
该配置规则:包含第一个参数时(索引从0开始,也就是p1)的请求访问超过1秒1次就限流。
参数例外项
上述案例演示了第一个参数p1,当QPS超过1秒1此点击后马上被限流
特例情况:我们期望p1参数当它是某个特殊值时,它的限流值和平均不一样,假如p1等于5时,它的阈值可以达到200
从整体维度对应用入口流量进行控制,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
按资源名称限流:把微服务关了后,流控规则消失了,是临时的
@SentinelResource(value = "byResource", blockHandler = "handleException")
按照url地址限流:通过访问的url来限流,会返回sentinel自带默认的限流处理信息
@GetMapping("/rateLimit/byUrl") //把/rateLimit/byUrl当做资源名在控制台配置,不使用下面的byUrl
@SentinelResource(value = "byUrl")
上面兜底方案面临的问题:
系统默认的,没有体现我们自己的业务要求
自定义的处理方法有和业务代码耦合在一块,不直观
每个业务代码都添加一个兜底的,代码膨胀加剧
全局统一的处理方法没有体现
自定义限流处理逻辑:
(1)创建CustomerBlockHandler类用于自定义限流处理逻辑
public class CustomerBlockHandler {
public static CommonResult handleException1(BlockException exception) {
return new CommonResult(4444, "自定义限流处理信息....handleException---1");
}
public static CommonResult handleException2(BlockException exception) {
return new CommonResult(4444, "自定义限流处理信息....handleException---2");
}
}
(2)Controller使用
//自定义限流处理逻辑
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, //自定义限流处理类
blockHandler = "handlerException2") //自定义限流处理类里的哪个方法为你兜底
Sentinel整合ribbon+openFeign+fallback
(1)创建Maven工程为服务提供者(cloudalibaba-provider-payment9003/9004)
(2)application.yml
server:
port: 9003 //记得修改不同的端口
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos注册中心地址
management:
endpoints:
web:
exposure:
include: '*'
(3)启动类上加@EnableDiscoveryClient
(4)创建Maven工程为服务消费者(cloudalibaba-consumer-nacos-order84)
(5)application.yml
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心
sentinel:
transport:
dashboard: localhost:8080 #sentinel控制台地址,使8080监控84
port: 8719
service-url:
nacos-user-service: http://nacos-payment-provider #去nacos注册中心访问nacos-payment-provider微服务
(6)启动类上加@EnableFeignClients、@EnableDiscoveryClient
(7)Controller
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
exceptionsToIgnore = {IllegalArgumentException.class}) //exceptionsToIgnore忽略的异常,报了该异常不再兜底
public CommonResult fallback(@PathVariable Long id) {
CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id, CommonResult.class,id);
if (id == 4) {
throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
}else if (result.getData() == null) {
throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
//fallback
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
//blockHandler
public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}
(8)测试: 没有配置@SentinelResource,给用户error页面
配置了fallback和blockHandler都配置,blockhandler最大。
(1)openfeign只跟消费侧有关,修改84
(2)假如openFeign依赖
org.springframework.cloud
spring-cloud-starter-openfeign
(3)在yml激活Sentinel对openFeign的支持
feign:
sentinel:
enabled: true
(3)测试84调用9003,此时故意关闭9003,84端自动降级,不会被耗死