赞
踩
所谓资源就是 Sentinel 要保护的东西,资源是 Sentinel 的关键概念。它可以是Java应用程序中的任何内容,可以是一个服务,也可以是一个方法,甚至可以是一段代码。
我们入门案例中的 message1 方法就可以认为是一个资源。
规则就是用来定义如何进行保护资源的。规则作用在资源之上,定义以什么样的方式保护资源,主要包括流量控制规则、熔断降级规则以及系统保护规则。
我们入门案例中就是为 message1 资源设置了一种流控规则,限制了进入message1的流量。
Sentinel 的主要功能就是容错,主要体现为:
流量控制在网络传输中是一个常用的概念,它用于调整网络包的数据。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状。
当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
Sentinel对这个问题采取了两种手段:
Sentinel和Hystrix对熔断降级处理的区别
两者的原则是一致的,都是当一个资源出现问题时,让其快速失败,不要波及到其它服务。但是在限制的手段上,却采取了完全不一样的方法:
Sentinel 同时提供系统维度的自适应保护能力。当系统负载较高的时候,如果还持续让请求进入可能会导致系统崩溃,无法响应。
在集群环境下,会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候, Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
总之一句话:我们需要做的事情,就是在 Sentinel 的资源上配置各种各样的规则,来实现各种容错的功能。
流量控制,其原理是监控应用流量的QPS(每秒查询率)或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
点击簇点链路,我们就可以看到访问过的接口地址,然后点击对应的流控按钮,进入流控规则配置页面。新增流控规则界面如下:
接下来我们以QPS为例来研究限流规则的配置。
我们先做一个简单配置,设置阈值类型为QPS,单机阈值为3。即每秒请求量大于3的时候开始限流。接下来,在流控规则页面就可以看到这个配置。
点击上面设置流控规则的编辑按钮,然后在编辑页面点击高级选项,会看到有流控模式一栏
sentinel 共有三种流控模式,分别是:
下面呢分别演示三种模式:
直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。上面案例使用的就是直接流控模式。
关联流控模式指的是,当指定接口关联的接口达到限流条件时,开启对指定接口开启限流。
第1步:配置限流规则,将流控模式设置为关联,关联资源设置为的 /order/message2
第2步:通过 Apache JMeter 软件向 /order/message2 连续发送请求,注意QPS一定要大于3
第3步:通过浏览器访问/order/message1
,会发现已经被限流
链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流。它的功能有点类似于【针对来源配置项】,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。
第1步:编写一个Service,在里面添加一个方法 message
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, ShopOrder> implements IOrderService {
@Override
@SentinelResource("message")
public void message() {
System.out.println("message");
}
}
第2步:在Controller中声明两个方法,分别调用service中的方法message
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController3 {
@Autowired
private IOrderService orderService;
@RequestMapping("/message1")
public String message1() {
orderService.message();
return"message1";
}
@RequestMapping("/message2")
public String message2() {
orderService.message();
return"message2";
}
}
第3步:禁止收敛URL的入口context
从1.6.3版本开始,SentinelWebFluxFilter默认收敛所有URL的入口context,因此链路限流不生效。
1.7.0版本开始(对应SCA的2.1.1.RELEASE
),官方在CommonFilter引入了WEB_CONTEXT_UNIFY
参数,用于控制是否收敛 context 。将其配置为 false 即可根据不同的URL 进行链路限流。
SCA 2.1.1.RELEASE
之后的版本,可以通过配置spring.cloud.sentinel.web-context-unify=false
即可关闭收敛。我们当前使用的版本是Spring Cloud Alibaba 2.1.0.RELEASE
,无法实现链路限流。
目前官方还未发布SCA 2.1.2.RELEASE
,所以我们只能使用2.1.1.RELEASE
,需要写代码的形式实现
(1)暂时将Spring Cloud Alibaba
的版本调整为2.1.1.RELEASE
,如果引入的依赖加了版本号也记得改一下
<spring-cloud-alibaba.version>2.1.1.RELEASE</spring-cloud-alibaba.version>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
(2)配置文件中关闭 sentinel 的 CommonFilter 实例化
spring:
cloud:
sentinel:
filter:
enabled: false
(3)添加一个配置类,自己构建CommonFilter实例
@Configuration
public class FilterContextConfig {
@Bean
public FilterRegistrationBean sentinelFilterRegistration(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new CommonFilter());
filterRegistrationBean.addUrlPatterns("/*");
//入口资源关闭聚合
filterRegistrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false");
filterRegistrationBean.setName("sentinelFilter");
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
}
第4步:控制台配置限流规则
第5步:分别通过/order/message1
和/order/message2
访问,发现2没问题,1的被限流了
熔断规则就是设置当满足什么条件的时候,对服务进行熔断。Sentinel提供了三个衡量条件:
在1000ms内,请求至少有10个的情况下,出现了大于等于10%的请求调用时间大于100毫秒,则在3秒内会自动熔断,触发降级。
参数解释:
注意 Sentinel 默认统计的RT上限是 4900 ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项
-Dcsp.sentinel.statistic.max.rt=xxx
来配置。
如图所示,即/order/message2接口,在1000ms内,请求至少有5个的情况下,出现了大于等于10%的请求抛出了异常,则在3秒内会自动熔断,触发降级。
第1步:首先模拟一个异常
int i = 0;
@RequestMapping("/message2")
public String message2() {
i++;
if(i%3==0){
throw new RuntimeException();
}
return"message2";
}
第2步:设置异常比例为0.25
不想用 Apache JMeter 进行测试的小伙伴,可以直接使用 Apifox 进行测试,首先选中左侧tab中的【自动化测试】,然后选择【添加测试场景】
【添加步骤】选择【添加自定义请求】
添加自己的请求,保存并返回,在右侧设置好运行参数,然后点击【运行】按钮。
此时再在浏览器去访问/order4/message2
接口就会出现Blocked by Sentinel (flow limiting)
信息。
在一秒内,请求至少有5个的情况下,出现了大于等于一个的请求抛出了异常,则在3秒内会自动熔断,触发降级。
热点参数流控规则是一种更细粒度的流控规则,它允许将规则具体到参数上。
@RequestMapping("/message3")
//注意这里必须使用这个注解标识,否则热点规则不生效
@SentinelResource("message3")
public String message3(String name,String age) {
return name + age;
}
【参数例外项】允许对一个参数的具体值进行流控。编辑刚才定义的规则,增加【参数例外项】
参数值为zha,限流阈值为10,这样当访问路径上第一个参数name的值为zha时,在一秒(统计窗口时长)内访问超过10次(单机阈值)才会发生限流,如果第一个参数name的值不是zha时,限流的阈值还是1,如果不带参数name不会触发限流,注意指定的参数类型要与方法的参数类型保持一致。
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用Sentinel的来源访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:
上面的资源名和授权类型不难理解,但是流控应用怎么填写呢?
其实这个位置要填写的是来源标识,Sentinel 提供了 RequestOriginParser 接口来处理来源。只要 Sentinel 保护的接口资源被访问,Sentinel 就会调用 RequestOriginParser 的实现类去解析访问来源。
@Service
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String serviceName = httpServletRequest.getParameter("serviceName");
return serviceName;
}
}
http://localhost:8091/order4/message1?serviceName=pc
返回Blocked by Sentinel (flow limiting)
系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口QPS、CPU使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量(进入应用的流量)生效。
maxQps*minRt
计算得出。设定参考值一般是 CPU cores*2.5
。@Component
public class ExceptionHandlerPage implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
//BlockException 异常接口,包含Sentinel的五个异常
// @SentinelResource 用于定义资源,并提供可选的异常处理和fallback 配置项。其主要参数如下:
// FlowException 限流异常
// DegradeException 降级异常
// ParamFlowException 参数限流异常
// AuthorityException 授权异常
// SystemBlockException 系统负载异常
BlockException e) throws IOException {
httpServletResponse.setContentType("application/json;charset=utf-8");
ResponseData data = null;
if(e instanceof FlowException) {
data = new ResponseData(-1, "接口被限流了…");
}else if (e instanceof DegradeException){
data= new ResponseData(-2, "接口被降级了…");
}
httpServletResponse.getWriter().write(JSON.toJSONString(data));
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResponseData {
private int code;
private String message;
}
到这儿,服务容错中间件Sentinel的概念和功能以及五大规则就已经介绍完了。下一篇将为大家带来容错组件 Sentinel 的规则持久化的文章,敬请期待吧!
后续的文章,我们将继续完善我们的微服务系统,集成更多的Alibaba组件。想要了解更多JAVA后端知识,请点击文末名片与我交流吧。留下您的一键三连,让我们在这个寒冷的东西互相温暖吧!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。