1.Sentinel和Hystrix
1.1.限流和熔断
限流 , 限制流量,这里的流量我们可以理解成请求数量,其实就是限制服务器的请求并发数量,为什么要这么做?如果不做限流,那么在大量并发请求下我们的服务器会慢慢的变慢然后顶不住压力而挂掉(类似堵车)。并不是说并发越大越好,有的时候我们的项目规模和业务决定了我们不需要那么大的并发性,当大量的并发请求访问到服务器时我们需要把部分请求拒绝在外,这个是流量限制 - 限流。
熔断机制在在《Spring Cloud 极简入门》中有详细的解释,熔断机制是对服务调用链路的保护机制,如果链路上的某个服务不可访问,调用超时,发生异常等,服务会进行发熔断,触发降级返回托底数据。简单理解就是当服务器不可访问,可以返回一些预先准备好的兜底数据给用户,比如友好的提示信息,不至于直接向客户抛出异常。
1.2.Hystrix的熔断和资源隔离
其实在《Spring Cloud 极简入门》中我们已经学习过Hystrix的熔断和资源隔离机制,它的资源隔离可以通过线程池隔离和信号量隔离两种方式来实现对流量的控制。Hystrix相比Sentinel来说它的线程池隔离(限流)会造成线程上下切换对资源的消耗比较大;Hystrix使用的信号量进行资源的隔离效果不错,但是无法对慢调用进行自动降级。
1.4.Sentinel介绍
Sentinel诞生于阿里巴巴,其主要目标是流量控制和服务熔断,2018年,Sentinel演变为一个开源项目现如今成为了Spring Cloud Alibaba的一个子项目。Sentinel是通过限制并发线程的数量(即信号隔离)来减少不稳定资源的影响,而不是使用线程池,省去了线程切换的性能开销。
当资源的响应时间变长时,线程将开始被占用。当线程数累积到一定数量时,新的传入请求将被拒绝。反之亦然,当资源恢复并变得稳定时,占用的线程也将被释放,新请求将被接受。
除了限制并发性外,Sentinel可以根据响应时间降级不稳定资源也是保证可靠性的有效方法。当资源的响应时间太大时,将在指定的时间窗口中拒绝所有对该资源的访问。-- 熔断机制
此外,Sentinel支持的熔断降级维度更多,可对多种指标进行流控、熔断,且提供了实时监控和控制面板,功能更为强大。
2.Sentinel限流实战
2.1.Sentinel Server服务端
Sentinel 提供了现成的服务端供我们使用,点我下载地址,下载之后通过命令行启动
java -jar -Dserver.port=1111 sentinel-dashboard-1.6.0.jar
访问:http://localhost:1111
进入控制台,使用 sentinel/sentinel登录。
注意:只有1.6.0及以上版本才有这个登录页面。默认用户名和密码都是sentinel
。对于用户登录的相关配置可以在启动命令中增加下面的参数来进行配置:
-Dsentinel.dashboard.auth.username=sentinel
: 用于指定控制台的登录用户名为 sentinel;-Dsentinel.dashboard.auth.password=123456
: 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel-Dserver.servlet.session.timeout=7200
: 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;-Dserver.port=1111
:配置端口
主页面效果
2.2.Sentinel 客户端接入
1.导入依赖
修改用户服务 springcloudalibaba-user-server-1010 ,加入sentinel依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.配置Sentinel
修改yml配置,添加senticel服务控制台地址
spring:
cloud:
sentinel:
transport:
dashboard: localhost:1111
3.资源限流
Sentinel为我们提供了 @SentinelResource
注解标记需要限流的资源。 修改UserController,代码如下:
@GetMapping("/user/{id}")
//限流降级
@SentinelResource(value="user",blockHandler="exceptionHandler")
public User getById(@PathVariable Long id){
System.out.println(notify);
return new User(id,"zs:"+id, "我是zs");
}
// 限流与阻塞处理 : 参数要和 被降级的方法参数一样
public User exceptionHandler(@PathVariable Long id, BlockException ex) {
ex.printStackTrace();
System.out.println("限流了...");
return new User(-1L,"限流了","限流了");
}
提示:这里通过@SentinelResource
的value属性为资源取名为 “user” ,后续我们可以根据该资源名来进行限流。
同时这里通过 blockHandler
属性我配置了一个限流降级方法,即当“user”资源触发限流了会调用blockHandler
指向的降级方法返回拖地数据,不至于抛出默认的限流异常信息给客户端(一串英文用户也看不懂) ,需要注意的是:降级方法要和被限流的方法参数一致,然后加上 BlockException异常对象。
当然,也可以通过 blockHandlerClass 属性把降级方法写在一个专门的类中,如:
@SentinelResource(value="user",blockHandler="exceptionHandler"
,blockHandlerClass=ExceptionUtil.Class)
降级类
public final class ExceptionUtil {
public static User exceptionHandler(Long id ,lockException ex) {
//...
}
}
2.3.Sentinel设置限流策略
启动应用 springcloudalibaba-user-server-1010 ,然后通过浏览器访问 http://localhost:1010/user/11
,然后登录Sentinel控制台,在“实时监控”列表中可以看到资源的相关监控信息的
在“族点链路”列表中可以看到资源的调用链 ,并且可以通过“流控”按钮设置流控规则
也可以在“流量控制”菜单中我们可以针对资源进行限流规则的设置。如下:
这里我添加了一个流控规则,资源名对应客户端 @SentinelResource(value="user"..
注解的资源,通过QPS限流(每秒请求数量),阈值是 1 ,意思是“user”这个资源每秒只能有1个请求进来,多余的请求会触发限流,返回降级数据。
2.4.限流测试
通过浏览器频发访问 “user”资源,当QPS大于1就会触发限流,效果如下:
2.5.总结
在这里我们探讨了Sentinel流控的简单使用,使用QPS方式进行流控。Sentinel还提供了非常强大的流控模式,继续往后看...
3.Sentinel流控模式
3.1.直接
Sentinel默认的流控处理就是【直接->快速失败】,QPS达到阈值,当前资源直接失败。在流控规则中配置如下:
3.2.关联
关联的资源达到某个阈值,限流自己,如:限流的资源是/user/delete
,关联的资源是/user/list
,当/user/list
达到阈值,限流user/delete
, 举例: 支付并发太高,可以限制下单的流量
3.3.链路
限流线路调用链路的入口,如 /user/list
资源中 调用了 /dept/list
,对/dept/list
添加限流,当/dept/list
达到阈值,其实限流的是/user/list
,因为他是访问的入口
4.Sentinel流控效果
4.1.快速失败
快速失败:(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)是默认的流控方式,当流量达到阀值直接返回异常,QPS达到任何规则阈值后,后续请求就会立即拒绝,并抛出FlowException 异常。简单理解:并发太高,直接请求拒绝
4.2.Warm Up预热
Warm Up预热:(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,根据codeFactor(默认3)的值,从(阀值/codeFactor)为初始阀值,经过预热时长,才到达设置的QPS的阀值,即预热/冷启动方式。简单理解:慢慢的增大处理并发的能力
提示:初始的QPS阈值为 100 / 3 =33 ,10秒后 QPS阈值达到 100.
当系统长期并发不高,流量突然增加可能会直接把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值的上限,给系统一个预热的时间,避免冷系统被压垮。
4.3.排队等待
排队等待(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER),忽然增加的请求并发量达到了限流阈值后续请求会被决绝,有时候我们可能更希望后续的请求可以加入队列进行排队,慢慢执行,而不是直接拒绝请求,这种方式后严格控制请求通过的时间间隔,也即是让请求以均匀的速度通过,对应的是漏桶算法,这种方式主要用于处理间隔性突发的流量,例如消息队列。 简单理解:突发流量处理不过来,让请求排队。
提示:QPS阈值为100,超过的请求会排队,排队超时时间为 10S
4.4.总结
上面介绍了Sentinel的流控模式和效果,小伙伴可以执行根据图例进行配置。
5.热点限流
还有一种特殊的动态限流规则,用于限制动态的热点资源 , 比如对同一个用户的请求频率做限定,比如对参数进行限定,比如对参数的值做限定(比如对商品ID为1的资源做限流)。
5.1.参数限流
参数限流就是 对资源的参数进行限流,我们来编写一个方法,接受两个参数:p1,和p2并设置好限流降级。
//限流降级
@SentinelResource(value="/parameterLimit",blockHandler="parameterLimitHandler")
@GetMapping(value="/parameterLimit")
public String parameterLimit(@RequestParam("p1") String p1 ,@RequestParam("p2") String p2){
return "parameterLimit方法调用成功...";
}
// 限流与阻塞处理
public String parameterLimitHandler(@RequestParam("p1") String p1 ,@RequestParam("p2") String p2,BlockException ex) {
return "限流了...";
}
配置热点规则 , 对第一个参数限流 , 当第一个参数超过了1的QPS就熔断降级。
5.2.参数值限流
对某一个参数的值满足某种条件的时候就进行限流,如下配置
意思是第一个参数的值为 haha 的时候限流阈值为10 , 超过 QPS > 10的并发就限流。
举例:应用场景比如说商品名称为“华为p40”的商品并发特别高,我们可以针对参数商品名为“华为p40”的商品进行限流。
6.系统规则
6.1.配置全局限流规则
系统规则可以看做是总的限流策略,所有的只要都要受到系统规则的限制。
上面的意思是最大并发只能允许 10 个线程数,并且是作用于全局的。
7.Gateway使用Sentinel限流
Spring Cloud Gateway 作为微服务的网关,它是微服务的访问入口,当请求的流量洪峰到来我们可以在Gateway网关层通过Sentinel对请求进行流控,把好第一道关。
7.1.导入依赖
这里我们需要导入sentinel基础依赖和 sentinel-gateway 整合依赖
<!-- 限流和gataway使用-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
7.1.配置Sentinel地址
修改yml配置,增加Sentinel服务地址
spring:
cloud:
sentinel:
transport:
dashboard: localhost:1111
7.2.配置限流规则
启动Gateway,登录sentinel控制台,对url资源进行流控限制,配置方式和前面的配置方式一样,童鞋们可以自己测试一下。
8.做个小结
我们看到,Sentinel有非常丰富的限流方式,比Hystrix更好用和强大,同学名需要自己动,根据上面的配置执行测试。