为什么使用Sentinel,这是一个高可用组件,为了使我们的微服务高可用而生
我们的服务会因为什么被打垮?
一,流量激增 缓存未预热,线程池被占满 ,无法响应
二,被其他服务拖垮,比如第三方的接口响应慢
三,异常没有处理:缓存击穿,缓存穿透等等
总之而言:系统缺乏可用性防护,没有容错机制,尤其是针对流量的防护会降低服务的可用性
服务雪崩:首先是积分系统服务挂掉了,一个系统不可用,导致整个微服务系统都不可用
限制流量
熔断
服务的降级 A计划-->B计划 积分服务就是一个弱依赖,和整体的流程关联不大,挂掉了也不会影响什么
有很多组件可以让我们进行流控、熔断、及降级,从中我们选择了SpringCloudAlibaba为我们提供的Sentinel这个组件作为我们项目中的保证服务高可用的组件。
https://github.com/alibaba/spring-cloud-alibaba/wiki
sentinel的说明文档
https://github.com/alibaba/spring-cloud-alibaba/blob/2.2.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
sentinel的控制台
https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
先了解一下如何接入 Sentinel
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
https://github.com/alibaba/Sentinel/releases 下载控制台 jar 包。此处下载的是1.8.5
Sentinel 控制台是一个标准的 Spring Boot 应用,以 Spring Boot 的方式运行 jar 包即可。
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.5.jar
注意:下载的版本的区别,不都是1.8.5
启动之后访问ip:8080
user/pwd sentinel/sentinel
在代码端(客户端):
pom中:
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
之后在application.yml文件中:主要是:spring.cloud.sentinel.transport.dashboard
server:
port: 8087
spring:
application:
name: order_nacos-sentinel
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
username: nacos
password: nacos
namespace: public
sentinel:
transport:
dashboard: localhost:8080
我们写的服务需要访问一次才能在dashboard中显示
访问了下列地址每个地址一次之后:
http://192.168.50.59:8087/order/getStock
http://192.168.50.59:8087/order/test1
http://192.168.50.59:8087/order/test2
http://192.168.50.59:8087/order/flow
之后,就可以发现:
给getStock设置一个QPS流控:
设置为1
我们继续访问http://192.168.50.59:8087/order/getStock,连续多点,会出现以下:
怎么改这个页面呢?
指定的blockHandler方法要求:
1.必须是public的 2.方法返回值必须和源方法相同 3.方法参数和源方法相同,最后一个方法参数是BlockException
继续快速访问
这里出现了一个问题:我的程序每次重新启动的时候,流控规则都消失了,因为现在这些规则是存放在内存中的,没有做持久化
也可以说是并发线程数流控
线程数流控和QPS流控有什么区别呢?
以一个为例:
qps为1的话代表每秒只允许有一个请求访问,
并发线程数为1的话,只要有一个线程访问,这个线程没有访问结束,那么其他线程就不能再次访问,测试的时候用睡眠的方式来测试。
@RequestMapping("/flow")
@SentinelResource(value = "getStock",blockHandler = "flowBlockException")
public String flow(){
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "QPS流控";
}
public String flowBlockException(BlockException e){
return "并发线程数流控";
}
如果不想用@SentinelResource
那么我们可以写一个类:实现:BlockExceptionHandler
@Component
@Slf4j
public class MyBlockException implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest
, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
if(e instanceof BlockException){
log.error("被流控了" + e.getRule());
}else if(e instanceof DegradeException){
log.error("被降级了" + e.getRule());
}
httpServletResponse.getWriter().print(e.getRule());
// new ObjectMapper().writeValue(httpServletResponse.getWriter(),e.getRule());
}
流控规则一般在服务的提供方,降级规则设置在服务的消费端。
当关联资源1被设置了以后限流以后,限制的不是自己,而是资源2的流控
这里会用到Jmeter这个测试工具,关于JMeter中文的设置(使用之前一定要配置好jdk)
性能测试(2): 测试工具 -- JMeter 安装和中文设置-腾讯云开发者社区-腾讯云
这里多写了一个简单的/add接口
启动测试计划以后访问:http://127.0.0.1:8087/order/getStock
访问不了,显示被流控了
想要使用这个功能,配置文件中,必须设置:spring.cloud.sentinel.web-context-unify 这个属性值默认为true,表示收敛调用链路的。
spring.cloud.sentinel.web-context-unify=false
要说明的是:进行流控的资源名不一定是controller中的接口,也有可能是service中的方法
controller中:
service中:
@Service
@Slf4j
public class OrderService {
@SentinelResource(value = "aa",blockHandler = "aaBlockException")
public String aa(){
log.info("测试链路流控...");
System.out.println("测试链路流控...");
return "测试链路流控...";
}
public String aaBlockException(BlockException e){
log.error(e.getRule()+" ~~~");
return "wawawawawwwawa";
}
}
测试的过程中会发现test3接口怎么测试都不会发生变化,test4访问速度过快就会显示wawawawawwwawa
1.快速失败
2.warm up 预热
针对激增流量突然涌入进来打垮冷系统,防止缓存击穿。刚开始QPS是(阈值/3) ,经过填写的预热时间增长到阈值
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量 突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐 增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。 冷加载因子: codeFactor 默认是3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
3.排队等待
针对脉冲流量
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下 来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的 请求。