文章目录
一、SpringCloud 微服务基础介绍
二、SpringCloud 微服务项目构建
三、SpringCloud 微服务之Eureka 服务注册与发现
四、SpringCloud 微服务之 Zookeeper 服务注册与发现
五、SpringCloud 微服务之Consul 服务注册与发现
六、SpringCloud 微服务之 Ribbon 负载均衡服务调用
七、SpringCloud 微服务之 OpenFeign 服务接口调用
八、SpringCloud 微服务之 Hystrix 断路器
九、Spring Cloud 微服务之 Gateway
十、SpringCloud 微服务之SpringCloud Config 分布式配置中心
十一、SpringCloud 微服务之SpringCloud Bus 消息总线
十二、SpringCloud 微服务之SpringCloud Stream 消息驱动
十三、Spring Cloud 微服务之 SpringCloud Sleuth 分布式请求链路跟踪
十四、SpringCloud Alibaba Nacos 服务注册和配置中心
十五、SpringCloud Alibaba Sentinel 实现熔断与限流
十六、SpringCloud Alibaba Seata 处理分布式事务
1. Sentinel 简介
1.1 官网:
https://github.com/alibaba/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
1.2 比较
1.3 是什么
1.4 下载地址
https://github.com/alibaba/Sentinel/releases
1.5 能干嘛
1.6 怎么用:解决哪些问题
- 服务雪崩
- 服务降级
- 服务熔断
- 服务限流
2. 安装Sentinel控制台
2.1 sentinel组件有两部分构成
- 核心库(Java客户端)不依赖任何框架/库,能够运行于所有Java运行时环境,同时对Dubbo/Spring Cloud等框架也有较好的支持。
- 控制台(Dashboard)基于SpringBoot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。
2.2 安装步骤
- 下载
https://github.com/alibaba/Sentinel/releases- 运行
前提:Java8环境、8080端口没被占用
命令:java -jar xxx.jar- 访问sentinel管理界面
http://ip:8080
登录账号密码均为sentinel
3. 初始化演示工程
3.1 在父项目中创建 cloud-alibaba-sentinel-service8401 服务module
1. 修改pom
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.zzx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-alibaba-sentinel-service8401</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- SpringCloud alibaba Nacos discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud alibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot 整合web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
2. 编写 yaml
server:
port: 8401
spring:
application:
name: cloud-alibaba-sentinel-service
cloud:
nacos:
discovery:
# Nacos 服务注册中心地址
server-addr: 47.107.124.79:8848
sentinel:
transport:
# 配置 sentinel dashboard地址
dashboard: 47.107.124.79:8080
# 默认8719端口,假如端口被占用会自动从8719开始一次+1扫描,直到找到未被占用的端口
port: 8719
# 当sentinel和微服务不在同一台机器上时,需配置微服务启动机器的ip
client-ip: 微服务ip
management:
endpoints:
web:
exposure:
include: '*'
4. 编写主启动类和业务类
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class MainSentinel8401 {
public static void main(String[] args){
SpringApplication.run(MainSentinel8401.class,args);
}
}
业务类 FlowLimitController
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
return "------------testA";
}
@GetMapping("/testB")
public String testB(){
return "------------testB";
}
}
5. 启动测试
- 启动 nacos、Sentinel
- 启动微服务 8401
- 启动微服务后查看sentinel控制台
发现什么也没有,sentinel采用的是懒加载
执行一次访问即可
效果:多次访问testA和testB接口,出现下图所示
4. 流控规则
4.1 基本介绍
进一步解释说明:
- 资源名;唯一名称,默认请求路径
- 针对来源:Sentinel 可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用改api的QPS达到阈值的时候,进行限流
- 线程数:当调用该api的线程数达到阈值的时候,进行限流
- 是否集群:不需要集群
- 流控模式:
- 直接:api达到限流条件时就直接限流
- 关联:当关联的资源达到阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)[api级别的针对来源]
- 流控效果:
- 快速失败:直接失败,抛异常
- Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效。
4.2 流控模式
1. 默认直接
直接 -> 快速失败
QPS方式:
- 添加流控规则
- 方式一:
- 方式二:
- 配置说明
- 测试
点击快速访问 http://localhost:8401/testA
结果:
线程数方式:
2. 关联
- 是什么
- 当关联的资源达到阈值就限流自己
- 当与A关联的资源B达到阙值后,就限流A自己
- B惹事,A挂了
- 配置testA
- postman模拟并发密集访问testB
创建 Collections 测试
- 测试
先在postman测试testB可以正常访问,然后Run Sentinel关联测试的Collections集合,然后访问testA
测试结果:
大批量线程高并发访问B,导致A失效了
3. 链路
-配置 testA
4.3 流控效果
1. 直接-快速失败
- 直接-快速失败(默认的流控处理)
直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
2. Warm Up (预热)
官网参考:https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81—%E5%86%B7%E5%90%AF%E5%8A%A8
默认coldFactor为3,即请求QPS从threshold/3开始,经过预热时长逐渐升至设定的QPS阙值。
- 应用场景
eg:秒杀系统在开启的瞬间会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可以慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。
3. 排队等待
- 注意:匀速排队只允许阈值为QPS模式
5. 服务降级
5.1 基本介绍
1. 说明
Sentinel 熔断降级会在调用链路中某个资源出现不稳定时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
挡子源被降级后,在接下来的降级时间窗口之内,对该资源的调用都将自动熔断(默认行为是抛出 DegradeException)
2. Sentinel 断路器
Sentinel的断路器是没有半开状态的
半开的状态系统自动去检测是否请求有异常,没有日常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考hystrix
在Sentinel 1.8.0及其以上,引入了半开状态,详情可参考官网
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
5.2 降级策略应用
1. 慢调用比例
是什么
测试 controller 新增 testD方法
@GetMapping("/testD") public String testD() { // 将线程暂停几秒钟 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } log.info("-------testD,测试 慢调用比例"); return "-------testD"; }
配置熔断规则
注意:测试时统计时长尽量设置小一点;eg 100ms
使用jmeter进行压测
20个线程,1ms,永远执行
设置好后执行
jmeter使用参考:https://blog.csdn.net/zhou_zhao_xu/article/details/119036090网页访问测试结果
2. 异常比例
- 是什么
- 新增 controller 方法
@GetMapping("/testE") public String testE() { log.info("-------testE,测试 异常比例"); int age = 10 / 0; return "-------testE,测试 异常比例"; }
- 配置熔断规则
- 测试
注意:需多次点击测试,要达到触发熔断阈值才会触发
3. 异常数
- 是什么
异常数是按照分钟统计的- 新增 controller 方法
@GetMapping("/testF") public String testF() { log.info("-------testF,测试 异常数"); int age = 10 / 0; return "-------testF,测试 异常数"; }
- 配置熔断规则
- 测试
注意:需多次点击测试,要达到触发熔断阈值才会触发
6. 热点key限流
- 是什么
6.1 基本配置使用
- 新增 controller 方法
@GetMapping("/testHotkey")
@SentinelResource(value = "testHotkey", blockHandler = "deal_testHotkey")
public String testHotkey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
log.info("p1 = {},p2 = {}", p1, p2);
return "-------testHotkey";
}
public String deal_testHotkey(String p1, String p2, BlockException blockException) {
return "-------deal_testHotkey";
}
- 配置热点规则
- 测试
多次连续点击访问测试会根据上面设置的规则限流,返回自定义处理模块逻辑代码结果,只要携带p1参数,多次连续访问就会限流
注意:热点key限流配置,请一定要配置自定义限流处理方法,不然会返回错误页
6.2 参数例外项
前提条件:热点参数的注意点,参数必须是基本类型或者String
- 配置
- 测试
多次连续点击测试,发现当值为5时,未进入限流,当值不为5时,进入限流
7. 系统规则
- 配置全局QPS
- 测试
一次连续点击每个接口,发现所有的接口都会被限流
8. @SentinelResource
8.1 按资源名称限流+后续处理
- 启动 nacos、sentinel
- 修改 8401 模块
-
引入依赖
<dependency> <groupId>com.zzx</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency>
-
yaml
-
业务类RateLimitController
```java
@RestController
public class RateLimitController {@GetMapping("/byResource") @SentinelResource(value = "byResource", blockHandler = "handleException") public CommonResult byResource() { return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial007")); } public CommonResult handleException(BlockException blockException) { return new CommonResult(444, blockException.getClass().getCanonicalName() + "\t服务不可用"); } } ```
-
- 配置流控规则
- 配置步骤及图形配置和代码关系
- 表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流
- 配置步骤及图形配置和代码关系
- 测试
连续多次访问此接口,限流后返回自定义信息
注意:上面的返回格式不是JSON而是XML格式,这是因为sentinel依赖中包含了 jackson-dataformat-xml 它会将数据默认转换为xml形式,只需要排除对应包中的这个jar包就可以了
排除后结果:正常结果和触发流控规则结果
8.2 按照URL地址限流+后续处理
注意:当使用URL地址限流时,就算自己配置了限流后续响应信息也不会触发,会使用系统默认的
8.3 上面兜底方案面临的问题
- 系统默认的,没有体现我们自己的业务要求。
- 按照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。
- 按照每个业务方法都添加一个兜底,代码膨胀加剧。
- 全局统一的处理方法没有体现。
8.4 客户自定义限流处理逻辑
- 创建自定义限流处理类 CustomerBlockHandler 用于自定义限流处理逻辑
- RateLimitController
- 启动微服务后先调用一次,使其在sentinel控制台可以找到
- 配置限流规则
- 测试
快速连续点击测试,发现限流后返回了我们自定义的限流响应信息
- 代码关系
8.5 更多注解属性说明
9. 服务熔断功能
9.1 sentinel整合ribbon
1. 在父项目中创建 cloud-alibaba-provider-payment9003/9004 生产者服务module
9004参考9003
1.1 pom
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.zzx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-alibaba-provider-payment9003</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- SpringCloud alibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringBoot 整合web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.zzx</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
1.2 编写 yaml 配置
server:
port: 9003
spring:
application:
name: cloud-alibaba-nacos-provider-service
cloud:
# Nacos 配置
nacos:
discovery:
server-addr: 47.107.124.79:8848 # 配置 Nacos 地址
# 暴露web端点
management:
endpoints:
web:
exposure:
include: '*'
1.3 编写启动类和业务类
启动类
@SpringBootApplication
@EnableDiscoveryClient
public class MainPayment9003 {
public static void main(String[] args){
SpringApplication.run(MainPayment9003.class,args);
}
}
业务类
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
/**
* 准备测试数据,也可以连数据库测试
*/
private static Map<Long, Payment> map = new HashMap<>();
static {
map.put(1L, new Payment(1L, "serial001"));
map.put(2L, new Payment(2L, "serial002"));
map.put(3L, new Payment(3L, "serial003"));
map.put(4L, new Payment(4L, "serial004"));
}
@GetMapping("/paymentSQL/get/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
log.info("Enter {} server,parameter is {}", serverPort, id);
Payment payment = map.get(id);
return new CommonResult<Payment>(200, "from mysql,serverPort = " + serverPort, payment);
}
}
1.4 启动测试
- 根据给定数据测试
- 查看是否注册进nacos中
2. 在父项目中创建 cloud-alibaba-nacos-consumer-order84 消费者服务module
注意事项:修改后请手动重启微服务,热部署对注解修改有时不生效
2.1 pom
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.zzx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-alibaba-nacos-consumer-order84</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- SpringCloud alibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- SpringCloud alibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringBoot 整合web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.zzx</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.2 编写 yaml 配置文件
server:
port: 84
spring:
application:
name: cloud-alibaba-nacos-consumer-order
cloud:
# Nacos 配置
nacos:
discovery:
server-addr: 47.107.124.79:8848 # Nacos 服务注册中心地址
# Sentinel 配置
sentinel:
transport:
# 配置 sentinel dashboard地址
dashboard: localhost:8080
# 默认8719端口,假如端口被占用会自动从8719开始一次+1扫描,直到找到未被占用的端口
port: 8719
# 消费者将要去访问的微服务地址
service-url:
nacos-user-service: http://cloud-alibaba-nacos-provider-service
2.3 编写启动类、配置类和业务类
启动类
@SpringBootApplication
@EnableDiscoveryClient
public class MainOrder84 {
public static void main(String[] args){
SpringApplication.run(MainOrder84.class,args);
}
}
配置类
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
自定义全局 fallback 类
public class CustomerFallbackHandler {
public static CommonResult fallbackHandler(Long id, Throwable throwable) {
return new CommonResult(500, "id = " + id + " " + throwable.getMessage());
}
}
自定义全局 sentinel 默认返回信息
public class CustomerBlockHandler {
public static CommonResult blockHandler(Long id, BlockException blockException) {
return new CommonResult(444, "id = " + id + " " + blockException.getClass().getCanonicalName());
}
}
业务类
@RestController
@Slf4j
public class CircleBreakerController {
@Value("${service-url.nacos-user-service}")
private String serviceUrl;
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/get/{id}")
//@SentinelResource(value = "fallback") // 没有配置
// fallback只负责业务异常
@SentinelResource(value = "fallback", fallbackClass = CustomerFallbackHandler.class, fallback = "fallbackHandler")
// blockHandler 只负责 Sentinel 控制台输出
//@SentinelResource(value = "fallback", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "blockHandler")
/*@SentinelResource(value = "fallback", fallbackClass = CustomerFallbackHandler.class, fallback = "handlerFallback",
blockHandlerClass = CustomerBlockHandler.class, blockHandler = "blockHandler")*/
public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
CommonResult<Payment> result = restTemplate
.getForObject(serviceUrl + "/paymentSQL/get/" + id,
CommonResult.class, id);
if (id == 5) {
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException,该id没有对应的记录");
}
return result;
}
}
2.4 测试
依次启动9003、9004、84,并查看是否注册进了nacos中
1. 当没有配置时
返回信息不友好
2. 只配置 fallback时
3. 只配置 blockHandler 时
- 修改代码
- 新增熔断规则
- 多次点击测试
达到阈值后触发降级限流
4. fallback 和blockHandler 都配置
- 修改代码
- sentinel 对 fallback 新增流控规则
- 启动测试
- 注意:若blockHandler和fallback都进行了配置,则被降级限流而抛出BlockException时只会进入blockHandler处理逻辑
5. 忽略属性
- 修改代码
- 测试
- 结果
当忽略的一场出现时,不会进入fallback方法,会直接返回给前端
9.2 sentinel整合openFeign
1. 在父项目中创建 cloud-alibaba-nacos-openfeign-consumer-order85 消费者服务module
1.1 pom
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.zzx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-alibaba-nacos-openfeign-consumer-order85</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- SpringCloud alibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- SpringCloud openFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringCloud alibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringBoot 整合web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.zzx</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
1.2 编写 yaml 配置文件
server:
port: 85
spring:
application:
name: cloud-alibaba-nacos-consumer-order
cloud:
# Nacos 配置
nacos:
discovery:
server-addr: 47.107.124.79:8848 # Nacos 服务注册中心地址
# Sentinel 配置
sentinel:
transport:
# 配置 sentinel dashboard地址
dashboard: localhost:8080
# 默认8719端口,假如端口被占用会自动从8719开始一次+1扫描,直到找到未被占用的端口
port: 8719
# 启用 Sentinel 对 feign 的支持
feign:
sentinel:
enabled: true
1.3 编写启动类、业务类、自定义fallback、blockHandler、controller
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class MainOrder85 {
public static void main(String[] args){
SpringApplication.run(MainOrder85.class,args);
}
}
业务类
@FeignClient(value = "cloud-alibaba-nacos-provider-service")
public interface PaymentService {
@GetMapping("/paymentSQL/get/{id}")
CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackServiceImpl implements PaymentService {
@Override
public CommonResult<Payment> paymentSQL(Long id) {
return new CommonResult<>(444, "服务降级返回,-------PaymentFallbackServiceImpl");
}
}
controller
@RestController
public class CircleBreakerController {
private final PaymentService paymentService;
@Autowired
public CircleBreakerController(PaymentService paymentService) {this.paymentService = paymentService;}
@GetMapping("/feign/consumer/paymentSQL/get/{id}")
public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
CommonResult result = paymentService.paymentSQL(id);
return result;
}
}
启动时遇见报错:Caused by: java.lang.AbstractMethodError: com.alibaba.cloud.sentinel.feign.SentinelContractHolder.parseAndValidatateMetadata(Ljava/lang/Class;)Ljava/util/List;
新建包 com.alibaba.cloud.sentinel.feign 添加 SentinelContractHolder
参考:https://blog.csdn.net/zhou_zhao_xu/article/details/119781758
public class SentinelContractHolder implements Contract {
private final Contract delegate;
public final static Map<String, MethodMetadata> METADATA_MAP = new HashMap<>();
public SentinelContractHolder(Contract delegate) {
this.delegate = delegate;
}
@Override
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
List<MethodMetadata> metadatas = delegate.parseAndValidatateMetadata(targetType);
metadatas.forEach(metadata -> METADATA_MAP
.put(targetType.getName() + metadata.configKey(), metadata));
return metadatas;
}
}
熔断框架比较
Sentinel | Hystrix | Resilience4j | |
---|---|---|---|
隔离策略 | 信号量增高(并发线程数限流) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于RxJava) | Ring Bit Buffer |
动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个拓展点 | 插件的形式 | 接口的形式 |
基于注解支持 | 支持 | 支持 | 支持 |
限流 | 基于QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的Rate limiter |
系统自适应保护 | 支持 | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
10. 规则持久化
- 是什么
一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化- 怎么用
将限流规则持久化进Nacos保存,只要刷新8402某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8402上sentinel上的流控规则持续有效
持久化应用
1. 在父项目中创建 cloud-alibaba-sentinel-service8402 服务module
1.1 pom
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.zzx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-alibaba-sentinel-service8401</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- SpringCloud alibaba Nacos discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud alibaba sentinel-datasource-nacos 做持久化 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.zzx</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- SpringCloud alibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot 整合web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
1.2 编写 yaml 配置
server:
port: 8402
spring:
application:
name: cloud-alibaba-sentinel-service
cloud:
nacos:
discovery:
# Nacos 服务注册中心地址
server-addr: 47.107.124.79:8848
sentinel:
transport:
# 配置 sentinel dashboard地址
# dashboard: 47.107.124.79:8080
dashboard: localhost:8080
# 默认8719端口,假如端口被占用会自动从8719开始一次+1扫描,直到找到未被占用的端口
port: 8719
# client-ip: 42.120.75.130
datasource:
dsl:
nacos:
server-addr: 47.107.124.79:8848
dataId: cloud-alibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
management:
endpoints:
web:
exposure:
include: '*'
1.3 编写启动类、业务类、自定义限流返回信息类
启动类
@SpringBootApplication
@EnableDiscoveryClient
public class MainSentinel8402 {
public static void main(String[] args){
SpringApplication.run(MainSentinel8402.class,args);
}
}
自定义限流返回信息类
public class CustomerBlockHandler {
public static CommonResult handleException(BlockException blockException) {
return new CommonResult(2021,
blockException.getClass().getCanonicalName(),
"客户自定义 global CustomerBlockHandler handleException");
}
}
业务类
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial007"));
}
public CommonResult handleException(BlockException blockException) {
return new CommonResult(444, blockException.getClass().getCanonicalName() + "\t服务不可用");
}
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl", blockHandler = "handleException")
public CommonResult byUrl() {
return new CommonResult(200, "按URL限流测试OK", new Payment(2021L, "serial009"));
}
/**
* 用户自定义限流返回信息
*
* @return
*/
@GetMapping("/customize")
@SentinelResource(value = "customize",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handleException")
public CommonResult customize() {
return new CommonResult(200, "按用户自定义OK", new Payment(2021L, "serial010"));
}
}
1.4 添加 Nacos 配置规则
[
{
"resource": "/rateLimit/byUrl",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
启动8402服务,刷新sentinel发现业务规则有了
1.5 测试
- 快速访问测试接口,发现限流规则起作用了
- 停止8402服务,再次查看sentinel
- 再次启动8402服务
刚启动时sentinel中流控规则还是没有出现,多次调用测试接口
配置重新出现,持久化验证通过