一、初识Sentinel
1.1.雪崩问题及解决⽅案
1.1.1.雪崩问题
微服务中,服务间调⽤关系错综复杂,⼀个微服务往往依赖于多个其它微服务。服务器⽀持的线程和并发数有限,请求⼀直阻塞,会导致服务器资源耗尽,从⽽导致所有其它服务都不可⽤,那么当前服务也就不可⽤了。 那么,依赖于当前服务的其它服务随着时间的推移,最终也都会变的不可⽤,形成级联失败,雪崩就发⽣了:
解决雪崩问题的常⻅⽅式有四种:
1.1.2.超时处理
超时处理:设定超时时间,请求超过⼀定时间没有响应就返回错误信息,不会⽆休⽌等待
1.1.3.仓壁模式
于此类似,我们可以限定每个业务能使⽤的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。
1.1.4.断路器
断路器模式:由断路器统计业务执⾏的异常⽐例,如果超出阈值则会熔断该业务,拦截访问该业务的⼀ 切请求。
1.1.5.限流
流量控制:限制业务访问的QPS,避免服务因流量的突增⽽故障。
1.2.服务保护技术对⽐
在SpringCloud当中⽀持多种服务保护技术:
- Netfix Hystrix
- Sentinel
- Resilience4J
早期⽐较流⾏的是Hystrix框架,但⽬前国内实⽤最⼴泛的还是阿⾥巴巴的Sentinel框架,这⾥我们做下对⽐:
1.3.Sentinel介绍和安装
Sentinel是阿⾥巴巴开源的⼀款微服务流量控制组件。官⽹地址:https://sentinelguard.io/zh cn/index.html
1下载
2运⾏
将jar包放到任意⾮中⽂⽬录,执⾏命令:
java -jar sentinel-dashboard-1.8.1.jar
3访问
访问http://localhost:8080⻚⾯,就可以看到sentinel的控制台了:
需要输⼊账号和密码,默认都是:sentinel
登录后,发现⼀⽚空⽩,什么都没有:
这是因为我们还没有与微服务整合;懒加载
1.4.微服务整合Sentinel
1引⼊sentinel依赖
<!--sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
2配置控制台
修改application.yaml⽂件,添加下⾯内容:
3访问order-service的任意端点
打开浏览器,访问http://localhost:8091/order/prod/19,这样才能触发sentinel的监控。 然后再访问sentinel的控制台,查看效果
二、流量控制
雪崩问题虽然有四种⽅案,但是限流是避免服务因突发的流量⽽发⽣故障,是对微服务雪崩问题的预 防。
2.1.簇点链路
当请求进⼊微服务时,⾸先会访问DispatcherServlet,然后进⼊Controller、Service、Mapper,这样的 ⼀个调⽤链就叫做簇点链路。簇点链路中被监控的每⼀个接⼝就是⼀个资源。
默认情况下sentinel会监控SpringMVC的每⼀个端点(Endpoint,也就是controller中的⽅法),因此 SpringMVC的每⼀个端点(Endpoint)就是调⽤链路中的⼀个资源。
流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后⾯的按钮来设置规 则:
- 流控:流量控制
- 降级:降级熔断
- 热点:热点参数限流,是限流的⼀种
- 授权:请求的权限控制
2.2.流控模式
在添加限流规则时,点击⾼级选项,可以选择三种流控模式:
- 直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
- 关联:统计与当前资源相关的另⼀个资源,触发阈值时,对当前资源限流
- 链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流
三、隔离和降级
3.1.FeignClient整合Sentinel
SpringCloud中,微服务调⽤都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。
3.1.1.修改配置,开启sentinel功能
feign: sentinel: enabled: true
3.1.2.编写失败降级逻辑
YAML 业务失败后,不能直接报错,⽽应该返回⽤户⼀个友好提示或者默认结果,这个就是失败降级逻辑。
创建ProductServiceFallBack类实现降级⽅案编辑
@Component
@FeignClient(value="service-product", fallback = ProductServiceFallBack.class)
public class ProductServiceFallBack implements IProductService {
@Override
public Products findByPid(Integer pid) {
Products product = new Products();
product.setPid(-1);
product.setPname(" 暂⽆商品 ");
return product;
}
}