基础
特点:懒加载
运行命令
java -jar sentinel-dashboard-1.8.1.jar
指定端口号运行
java -Dserver.port=9090 -jar sentinel-dashboard-1.8.1.jar
使用步骤
- 导入依赖
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
</parent>
<groupId>com.ape</groupId>
<artifactId>springboot_sentinel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<java.version>8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 统一管理版本 -->
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
</properties>
<modules>
<module>shop_common</module>
<module>shop_product</module>
<module>shop_order</module>
</modules>
<!-- 使用dependencyManagement管理 并且指定依赖版本 子项目就可以不用写版本了 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
- 子项目中导入依赖
XML
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
-
配置文件
spring:
cloud:
sentinel:
transport:
dashboard: localhost:9090
访问localhost:9090 输入用户与密码进入图形化界面 因为是懒加载所以没有信息
访问接口 localhost:8090/order/1 可以看到图形化界面中有了信息
流量控制
直接流量控制模式
- 添加流量控制
- 设置详情信息
- QPS即每秒查询率,QPS = req/sec = 请求数/秒,即每秒的响应请求数,也即是最⼤吞吐能⼒
关联流控模式
解释: 统计与当前资源相关的另⼀个资源,触发阈值时,对当前资源限流 假设A规则关联B,当B超过单机阈值那么A资源是受限制的
情景说明: ⽐如⽤户⽀付时需要修改订单状态,同时⽤户要查询订单。查询和修改操作会争抢数据库锁,产⽣竞争。业务需求是优先⽀付和更新订单 ,因此当修改订单业务触发阈值时,需要对查询订单业务限流。
1000个⽤户,100秒,因此QPS为10,超过了我们设定的阈值:5 请求的⽬标是/order/update,超过阈值后会对/order/query进行限流 /order/update不限流
链路流控模式
解释: 阈值统计时,只统计从指定资源进⼊当前资源的请求,是对请求来源的限流
举例: 有查询订单和更新订单业务,两者都需要查询商品。针对从查询订单进⼊到查询商品的请求统计,并设置限流。
步骤:
- 在OrderService中添加⼀个queryGoods⽅法,不⽤实现业务 使用@SentinelResource("goods")注解使业务层暴露出来
java
@Override
@SentinelResource("goods")
public void queryGoods(){
System.out.println("查询商品");
}
- 在OrderController中,改造/order/query端点,调⽤OrderService中的queryGoods⽅法
java
@GetMapping("/query")
public String query(){
service.queryGoods();
return "查询订单";
}
- 在OrderController中添加⼀个/order/save的端点,调⽤OrderService的queryGoods⽅法
java
@PutMapping("/updateOrder")
public String update(){
service.queryGoods();
return "修改订单";
}
- 给queryGoods设置限流规则,从/order/query进⼊queryGoods的⽅法限制QPS必须⼩于2
链路模式中,是对不同来源的两个链路做监控。但是sentinel默认会给进⼊SpringMVC的所有请求设置同 ⼀个root资源,会导致链路模式失效。 我们需要关闭这种对SpringMVC的资源聚合,修改order-service服务的application.yml⽂件:
spring:
cloud:
sentinel:
web-context-unify: false # 关闭Context整合
流控效果
快速失败
达到阈值后,新的请求会被⽴即拒绝并抛出FlowException异常。是默认的处理⽅式。
warm up
预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从⼀个较⼩值逐渐增加到最⼤阈值。
冷启动的 默认阈值= 最大阈值/3
对/order/query 最大限流为一秒10个请求 那么冷启动的阈值为 10/3 = 3 在5秒后达到最大阈值10
这个配置的意思就是在5秒后 达到最大阈值10
排队等待
当请求超过QPS阈值时,快速失败和 warm up 会拒绝新的请求并抛出异常。
排队等待则是让所有请求进⼊⼀个队列中,然后按照阈值允许的时间间隔依次执⾏。后来的请求必须等待前⾯执⾏完成,如果请求预期的等待时间超出最⼤时⻓,则会被拒绝。
⼯作原理 例如:QPS = 5,1s处理5个请求,意味着每200ms处理⼀个请求;timeout = 2s,意味着预期等待时⻓超过 2s的请求会被拒绝并抛出异常。
那什么叫做预期等待时⻓呢? ⽐如现在⼀下⼦来了12 个请求,因为每200ms执⾏⼀个请求,那么:
第6个请求的预期等待时⻓ = 200 * (6 - 1) = 1000ms
第12个请求的预期等待时⻓ = 200 * (12-1) = 2200ms 超过2s就会失败
举例:
最大阈值为10 1s处理10个请求 每个请求要100ms 等待时间为5s 超过5s的等待请求会被拒绝
如果有300个请求在20s内完成 那么QPS就是15 超出了最大阈值
最后一个请求等待时间 = 100ms * (15-1) = 1400ms 在设置的超时时间之内,所以所有请求都能成功
此时将测试用例重新设置 QPS为30 那么最后一个的等待时间是 100ms * (30 - 1) = 2900ms还是可以成功
热点参数限流
刚才的配置中,对查询商品这个接⼝的所有商品⼀视同仁,QPS都限定为5. ⽽在实际开发中,可能部分商品是热点商品,例如秒杀商品,我们希望这部分商品的QPS限制与其它商 品不⼀样,⾼⼀些。那就需要配置热点参数限流的⾼级选项了
需求: 给/order/prod/{pid}这个资源添加热点参数限流,规则如下:
- 默认的热点参数规则是每1秒请求量不超过2
- 给1这个参数设置例外:每1秒请求量不超过10
使用流程:
-
controller层的方法添加注解
@SentinelResource("hot") //热点限流 必须要用这个注解
@GetMapping("/{id}")
public Order selectById(@PathVariable int id) {
return service.getById(id);
} -
添加规则
除了访问/order/1 阈值是5 访问其他的都是2
隔离和降级
限流是⼀种预防措施,虽然限流可以尽量避免因⾼并发⽽引起的服务故障,但服务还会因为其它原因⽽ 故障。 ⽽要将这些故障控制在⼀定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级⼿段了。
线程隔离之前讲到过:调⽤者在调⽤服务提供者时,给每个调⽤的请求分配独⽴线程池,出现故障时, 最多消耗这个线程池内资源,避免把调⽤者的所有资源耗尽。
熔断降级:是在调⽤⽅这边加⼊断路器,统计对服务提供者的调⽤,如果调⽤的失败⽐例过⾼,则熔断 该业务,不允许访问该服务的提供者了。 可以看到,不管是线程隔离还是熔断降级,都是对客户端(调⽤⽅)的保护。需要在调⽤⽅ 发起远程调 ⽤时做线程隔离、或者服务熔断。
⽽我们的微服务远程调⽤都是基于Feign来完成的,因此我们需要将Feign与Sentinel整合,在Feign⾥⾯ 实现线程隔离和服务熔断
FeignClient整合Sentinel
注意:配置文件中springcloud版本是Hoxton.SR8 如果是10 会有循环依赖的错误
-
配置文件添加以下内容
feign:
sentinel:
enabled: true # 开启feign对sentinel的⽀持 -
编写失败降级逻辑
java
package com.ape.shop_order.service.impl;
import com.ape.pojo.Product;
import com.ape.shop_order.service.ProductService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
//降级方案
@Component
public class ProductServiceFallBack implements FallbackFactory<ProductService> {
@Override
public ProductService create(Throwable throwable) {
return new ProductService() {
@Override
public Product selectById(int id) {
Product product = new Product();
product.setPid(-1);
product.setPName("暂无商品");
return product;
}
};
}
}
- 发通信的接口
@FeignClient(value = "server-product",fallbackFactory = ProductServiceFallBack.class)
java
package com.ape.shop_order.service;
import com.ape.pojo.Product;
import com.ape.shop_order.service.impl.ProductServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "server-product",fallbackFactory = ProductServiceFallBack.class)
public interface ProductService {
@GetMapping("/product/{id}")
Product selectById(@PathVariable int id);
}