概要
Sentinel诞生于阿里巴巴,其主要目标是流量控制和服务熔断
,2018年,Sentinel演变为一个开源项目现如今成为了Spring Cloud Alibaba的一个子项目。Sentinel是通过限制并发线程的数量来减少不稳定资源的影响
,而不是使用线程池,省去了线程切换的性能开销。
当资源的响应时间变长时,线程将开始被占用。当线程数累积到一定数量时,新的传入请求将被拒绝
。反之亦然,当资源恢复并变得稳定时,占用的线程也将被释放,新请求将被接受。
除了限制并发性外,Sentinel可以根据响应时间降级
不稳定资源也是保证可靠性的有效方法。当资源的响应时间太大时,将在指定的时间窗口中拒绝所有对该资源的访问
。-- 熔断机制
此外,Sentinel支持的熔断降级维度更多,可对多种指标进行流控、熔断,且提供了实时监控和控制面板,功能更为强大。
Sentienl限流
1.Sentinel和Hystrix
1.1、限流和熔断
限流 , 限制流量,这里的流量我们可以理解成请求数量,其实就是限制服务器的请求并发数量,为什么要这么做?如果不做限流,那么在大量并发请求下我们的服务器会慢慢的变慢然后顶不住压力而挂掉(类似堵车)。并不是说并发越大越好,有的时候我们的项目规模和业务决定了我们不需要那么大的并发性,当大量的并发请求访问到服务器时我们需要把部分请求拒绝在外,这个是流量限制 - 限流。
熔断机制是对服务调用链路的保护机制,如果链路上的某个服务不可访问,调用超时,发生异常等,服务会进行发熔断,触发降级返回托底数据。简单理解就是当服务器不可访问,可以返回一些预先准备好的兜底数据给用户,比如友好的提示信息,不至于直接向客户抛出异常。
1.2.Hystrix的熔断和资源隔离
其实在我们以及了解过Hystrix的熔断和资源隔离机制,它的资源隔离可以通过线程池隔离和信号量隔离两种方式来实现对流量的控制。Hystrix相比Sentinel来说它的线程池隔离(限流)会造成线程上下切换对资源的消耗比较大;Hystrix使用的信号量进行资源的隔离效果不错,但是无法对慢调用进行自动降级。
2.Sentinel限流实战
2.1.Sentinel Server服务端
Sentinel 提供了现成的服务端供我们使用,点我下载地址,下载之后通过命令行启动
java -jar -Dserver.port=1111 sentinel-dashboard-1.6.0.jar
访问:http://127.0.0.1:1111
进入控制台,使用 sentinel/sentinel登录。
注意:只有1.6.0及以上版本才有这个登录页面。默认用户名和密码都是sentinel
。
主页面效果:
2.2.项目中连接 Sentinel
1.导入依赖
在用户服务 springCloud-alibaba-servers-user 的pom.xml中加入sentinel依赖
<!-- 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,代码如下:
@RestController
@RefreshScope // 刷新配置
public class UserController {
@GetMapping("/user/{id}")
@SentinelResource(value = "getById",blockHandler = "exceptionHandler")
public User getById(@PathVariable("id")Long id){
return new User(id,"zs:"+id, "我是zs");
}
// 限流与阻塞处理,参数要和被降级的方法参数一样
public User exceptionHandler(@PathVariable("id")Long id, BlockException exception) {
return new User(-1L,"","限流了");
}
}
提示:这里通过@SentinelResource
的value属性为资源取名为 “getById” ,后续我们可以根据该资源名来进行限流。
4.Sentinel设置限流策略
启动应用 springCloud-alibaba-servers-user ,然后通过浏览器访问 http://localhost:10010/user/1
,然后登录Sentinel控制台,在“实时监控”列表中可以看到资源的相关监控信息的
在 “族点链路” 列表中可以看到资源的调用链 ,并且可以通过“流控”按钮设置流控规则
5.限流测试
通过浏览器频发访问 “user”资源,当QPS大于我们设置的阈值2就会触发限流,效果如下:
Gateway使用Sentinel限流
Spring Cloud Gateway 作为微服务的网关,它是微服务的访问入口,当请求的流量洪峰到来我们可以在Gateway网关层通过Sentinel对请求进行流控,把好第一道关。
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>
2.配置Sentinel地址
修改yml配置,增加Sentinel服务地址
spring:
cloud:
sentinel:
transport:
dashboard: localhost:1111
3.配置限流规则
启动Gateway,登录sentinel控制台,对url资源进行流控限制,配置方式和前面的配置方式一样,可以自己测试一下。
4.限流降级
@Configuration
public class SentinelConfig {
public SentinelConfig(){
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
return ServerResponse.ok().body(Mono.just("限流啦,请求太频繁"),String.class);
}
});
}
}
Nacos存储限流规则
1.整合Nacos持久化限流规则
第一步:导入基础依赖,springCloud-alibaba-servers-user为例子,在pom.xml增加Sentinel和Nacos持久化配置依赖 sentinel-datasource-nacos ,如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--Sentinel和Nacos做持久的-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.5.2</version>
</dependency>
</dependencies>
第二步:配置持久化nacos地址
spring:
profiles:
active: dev
cloud:
nacos:
config:
prefix: application-user # 配置前缀
file-extension: yaml # 后缀
group: DEFAULT_GROUP #默认分组
server-addr: localhost:8848 # 配置中心
sentinel:
transport:
dashboard: localhost:1111
datasource:
flow:
nacos: #限流持久配置
server-addr: localhost:8848 #使用nacos的持久
dataId: application-user-flow-dev #获取限流的数据源的dataId
groupId: DEFAULT_GROUP
rule-type: flow #类型:限流
Sentinel熔断
1.概述
1.1.什么是熔断
在上面我们了解了Sentinel的流控(限流)功能,Sentinel除了流控还提供了服务熔断和降级机制,服务之间的调用关系错综复杂,微服务的调用链上的某些服务资源不稳定(宕机,异常,超时)可能会导致可能请求的失败和请求的堆积,调用链产生连锁反应可能会导致整个微服务架构瘫痪
。服务熔断降级机制是保障高可用的重要措施之一。
1.2.Sentinel熔断
Sentinel的服务熔断机制会对调用链上的某个不稳定(宕机,异常,超时)的资源,做出请求限制,快速失败,避免影响到其它的服务而导致级联错误
。资源熔断后,在后续的一定时间(时间窗口)之内,对该服务的请求都自动熔断,抛出 DegradeException异常。
Sentinel拥有比Hystrix更强大和丰富的功能,能满足我们的各种应用场景,并且经历过淘宝双十一的考验,是微服务架构中熔断机制的不二选择。
2.Sentnel熔断实战
2.1.资源熔断降级
修改springCloud-alibaba-servers-user工程,修改UserController ,通过@SentinelResource
注解的fallback
属性指定降级方法。
@RestController
@RefreshScope // 刷新配置
public class UserController {
@GetMapping("/user/{id}")
@SentinelResource(value = "getById",blockHandler = "exceptionHandler",fallback = "getByIdFallback")
public User getById(@PathVariable("id")Long id){
int i = 1 / 0; //方法异常,触发熔断
return new User(id,"zs:"+id, "我是zs");
}
// 限流与阻塞处理,参数要和被降级的方法参数一样
public User exceptionHandler(@PathVariable("id")Long id, BlockException exception) {
return new User(-1L,"","限流了");
}
// 熔断降级,参数和返回值与源方法一致
public User getByIdFallback(@PathVariable("id")Long id) {
return new User(-1L,"","熔断了");
}
}
方法中通过 int i = 1 / 0;
模拟异常,然后会熔断触发降级调用降级方法 。 通过 fallback
属性指定熔断的降级方法 ,熔断方法参数也要和被熔断方法参数一致。
2.2.配置降级策略
在Sentinel控制台,在族点链路菜单中找到“getById”资源,然后点击“熔断”按钮添加降级策略,如下:
这里的降级策略为“慢调用比例”,大概意思是:如果并发数大于5 (QPS > 5) ,然后平均响应时间大于200毫秒,那么接下来的2秒钟之内对该资源的请求会被熔断降级。
2.3.测试熔断
启动springCloud-alibaba-servers-user工程,访问 http://localhost:10030/servers/order/order/1
,浏览器返回:
这里已经返回了托底数据,其实是因为“getById”资源方法中抛出了异常,触发了熔断降级。
3.Feign整合Sentinel熔断
Spring Cloud Alibaba是Spring Cloud的一个子项目,OpenFeign是Spring Cloud的客户端负载均衡器,使用Spring Cloud Alibaba依然可以很方便的集成OpenFeign,如果要使用OpenFeign作为服务客户端负载均衡,那么我们需要考虑OpenFeign开启Sentinel进行服务熔断降级。
4.1.开启Sentinel
OpenFeign与Sentinel组件集成除了引入sentinel-starter
依赖关系之外,还需要在属性文件中启用Sentinel支持:feign.sentinel.enabled=true
feign:
sentinel:
enabled: true #熔断
4.2.给Feign接口降级
这里跟Feign开启Hystrix降级一样,还是可以使用fallback属性
@FeignClient(value = "userServer",fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/user/{id}")
User getById(@PathVariable("id")Long id);
}
4.3.编写降级类
@Component
public class UserClientFallback implements UserClient{
@Override
public User getById(Long id) {
return new User(-1L,"","无此用户");
}
}
小结
Sentinel 是一个功能强大的流量控制组件,可以帮助开发人员保护应用程序免受流量过载和异常请求的影响,保证系统的稳定性和可靠性。