跳到主要内容

Sentinel

开原地址:https://github.com/alibaba/Sentinel

下载:https://github.com/alibaba/Sentinel/releases

中文文档:https://sentinelguard.io/zh-cn/index.html

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

特性:

安装控制台

下载运行 jar 包启动即可

java -jar sentinel-dashboard-1.7.0.jar

访问地址:http://localhost:8080/    账号/密码   sentinel/sentinel

初始化监控

增加一个新的模块用来测试 sentinel,cloudalibaba-sentinel-service8401

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>lichcloud</artifactId>
<groupId>cn.lichenghao.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>cloudalibaba-sentinel-service8401</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<!-- 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--持久化用-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 自定义通用 -->
<dependency>
<groupId>cn.lichenghao.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
</dependencies>
</project>

配置文件 application.yml

server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: 192.168.200.10:8848
sentinel:
transport:
dashboard: 192.168.200.10:8080
# 默认 8719,如果被占用就+1
port: 8719

management:
endpoints:
web:
exposure:
include: "*"

测试请求


@RestController
public class SentinelController {

@GetMapping("/testa")
public String testA() {
return "test a";
}

@GetMapping("/testb")
public String testB() {
return "test b";
}
}

主启动类

@SpringBootApplication
@EnableDiscoveryClient
public class SentinelService8401 {
public static void main(String[] args) {
SpringApplication.run(SentinelService8401.class, args);
}
}

启动服务后,查看Nacos 注册中心和 Sentinel 监控中心,需要发送请求后,Sentinel 监控中心才会有数据,如下所示。

流量规则

流控类型

流控规则有三种,分别为直接(默认)、关联、链路。

直接

api 达到限流的条件,直接限流。

直接在链路右侧上选择流控按钮,默认唯一资源名称就是请求路径(后面可以通过在代码上加注解来指定唯一资源名称),选择QPS阈值设置为1,其余默认后确定。

增加该流控规则后,如果该连接每秒请求次数超过1那么就会受到控制。如下所示:

阈值类型:

  • QPS:当调用 api 的QPS达到阈值的时候,进行限流;
  • 线程数:当调用 api 的线程数达到阈值的时候,进行限流;

关联

当关联的资源达到阈值的时候,就限流自己。如下:当 /testb 达到阈值,那么就会限制 /testa;

链路

该流控模式针对资源链路上的接口进行限流,例如:A、B 两个接口都调用某一资源 C,A -> C、B -> C 可以看成两个简单的链路,此时可以针对 C 配置链路限流,比如限制 A 调用 C,而 B 调用 C 则不受影响,它的功能有点类似于针对来源配置项,但链路流控是针对上级接口,它的粒度更细。

流控效果

快速失败

默认,给出失败提示。

该方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

预热

该方式主要用于系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮的情况。

其公式为:开始从 阈值/coldFactor(默认为3) ,经过预热时长后达到设置的阈值;

排队等待

匀速排队,让请求以均匀的速度通过,阈值类型必须设置为QPS,否则无效。

如下设置:请求每秒10次,超过的就排队,等待的超时时间为20秒。

这种方式严格控制了请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。具体的例子参见 PaceFlowDemo

该方式的作用如下图所示:

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

降级规则

https://sentinelguard.io/zh-cn/docs/circuit-breaking.html

降级策略有三种,平均响应时间,异常比例,异常数。

RT

平均响应时间,当1s 内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值,那么在接下来的时间窗口内,这个方法的调用会自动熔断。Sentinel默认统计的RT上限是4900ms,超出的都算4900ms,但可以通过启动配置参数 -Dcsp.sentinel.statistic.max.rt=xxx来修改默认配置。

所以该规则生效的前提:

  • 一秒持续进入5个以上请求
  • 平均响应时间 > 阈值

代码增加测试请求

@GetMapping("/testc")
public String testC() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "test c";
}

新增降级规则,该规则表示如果 QPS>5 && 请求在200ms内不能处理完毕,那么下个时间窗口将会被限流。

很显然我们的测试代码一次请求需要1s,一定会命中该策略。

使用 Jmeter测试并发请求:每秒10个请求;

启动测试后,在浏览器再次请求该方法就会被熔断保护;

异常比例

异常比例,当资源的每秒请求量 >=5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,在下个时间窗口内(秒级),对这个方法的调用会快速失败,异常比例范围:[0.01.0] 代表0100%。

所以该规则生效的前提:

  • 一秒持续进入5个及以上请求;
  • 异常比例 > 阈值;

代码增加测试请求,请求直接就会报错;

@GetMapping("/testd")
public String testD() {
System.out.println("测试异常比例!");
int a = 1 / 0;
return "test d";
}

增加降级配置,表示错误比例在达到20%,就会限流;

同样使用 Jmeter 测试请求,然后用浏览器访问该方法就会被限流保护;

异常数

异常数,当资源近1分钟的异常数据超过阈值之后会进行限流。分钟级别。

使用 Jmeter 测试,然后浏览器再次访问该方法会被限流,停掉 Jmeter 再下个时间窗口后,再次访问会出现错误页面。

热点规则

https://sentinelguard.io/zh-cn/docs/parameter-flow-control.html

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

基础流控

增加测试代码:

@SentinelResource 注解指定资源名称,以及降级后回调的方法代替默认的方法;

@GetMapping("/testHostKey")
@SentinelResource(value = "testHostKey", blockHandler = "testHostKeyHandler")
public String testHostKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "Hostkey Test ";
}

public String testHostKeyHandler(String p1, String p2, BlockException blockException) {
return "Hostkey Test testHostKeyHandler !";
}

增加热点规则:如下表示第一个参数的QPS达到阈值就会被熔断降级。

高级配置

增加 参数例外项 来为某个参数的值设置独立的限流效果。如下所示:

当第一个参数的值为100的时候,设置它的限流阈值为100;

那么限流效果:

系统规则

https://sentinelguard.io/zh-cn/docs/system-adaptive-protection.html

Sentinel 系统自适应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

就是在系统层面做流量的控制!

服务熔断

整合 ribbon + openFeign + fallback。

准备测试项目整合 Ribbon

生产者9004

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>lichcloud</artifactId>
<groupId>cn.lichenghao.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>cloudalibaba-provider-payment9004</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 自定义通用 -->
<dependency>
<groupId>cn.lichenghao.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
</dependencies>

</project>

配置文件 application.yml

server:
port: 9004
spring:
application:
name: cloudalibaba-provider-server
cloud:
nacos:
discovery:
server-addr: 192.168.200.10:8848
management:
endpoints:
web:
exposure:
include: "*"

启动测试类

package cn.lichenghao.springcloudalibaba;

import cn.lichenghao.springcloud.entity.CommentResult;
import cn.lichenghao.springcloud.entity.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@EnableDiscoveryClient
@SpringBootApplication
public class Payment9004 {
public static void main(String[] args) {
SpringApplication.run(Payment9004.class, args);
}

public static Map<Long, Payment> map = new HashMap<>();

static {
map.put(1L, new Payment(1L, "6aa79493-ed22-49f5-b52a-7e8a32131b3f"));
map.put(2L, new Payment(2L, "bef9935f-80fe-4501-8483-75d912e12646"));
map.put(3L, new Payment(3L, "c86a6afb-e29e-4000-a477-882296b824dd"));
}

@Value("${server.port}")
private String port;

@RestController
public class payController {
@GetMapping(value = "/payment/{id}")
public CommentResult<Payment> payment(@PathVariable Long id) {
return new CommentResult(200, "from " + port, map.get(id));
}
}
}

生产者9005

同 9004 就是端口不同

消费者84

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>lichcloud</artifactId>
<groupId>cn.lichenghao.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>cloudalibaba-consumer-order84</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 自定义通用 -->
<dependency>
<groupId>cn.lichenghao.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
</dependencies>

</project>

配置文件 application.yml

server:
port: 84
spring:
application:
name: cloudalibaba-consumer-order
cloud:
nacos:
discovery:
server-addr: 192.168.200.10:8848
sentinel:
transport:
dashboard: 192.168.200.10:8080
port: 8719

# 微服务名称
service-url:
nacos-user-service: http://cloudalibaba-provider-server

ribbon 配置

package springcloudalibaba.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {

@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}

测试代码

package springcloudalibaba.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
public class FirstController {

@Value("${service-url.nacos-user-service}")
private String serverUrl;

@Resource
private RestTemplate restTemplate;

@GetMapping(value = "/consumer/payment/{id}")
public String order(@PathVariable Long id) {
return restTemplate.getForObject(serverUrl + "/payment/" + id, String.class);
}
}

启动类

package springcloudalibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Order84 {
public static void main(String[] args) {
SpringApplication.run(Order84.class, args);
}
}

有了上面的测试代码后,演示服务熔断后的"兜底"处理。如果没有兜底方法话,会返回springboot 默认的错误页面,不是很友好!

  • fallback:只负责代码中的业务异常;
  • blockHandler:只负责sentinel配置相关的;
  1. 演示只有 fallback ,增加测试代码如下所示:
@RestController
public class SecondController {

@Value("${service-url.nacos-user-service}")
private String serverUrl;

@Resource
private RestTemplate restTemplate;

@SentinelResource(value = "testFallback", fallback = "fallbackHandler")
@GetMapping(value = "/consumer/fallback/{id}")
public CommentResult<Payment> order(@PathVariable Long id) {
CommentResult<Payment> result = restTemplate.getForObject(serverUrl + "/payment/" + id, CommentResult.class);
if (4L == id) {
throw new IllegalArgumentException("IllegalArgumentException 参数异常");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException 没有记录!");
}
return result;
}

public CommentResult<Payment> fallbackHandler(Long id, Throwable e) {
Payment payment = new Payment(id, "null");
return new CommentResult(444, "fallbackHandler :" + e.getMessage(), payment);
}
}

fallbackHandler 方法在在请求出现异常后,会进行兜底操作。

  1. 演示只有 blockHandler ,修改测试代码如下所示:
@RestController
public class SecondController {

@Value("${service-url.nacos-user-service}")
private String serverUrl;

@Resource
private RestTemplate restTemplate;

@SentinelResource(value = "testFallback", blockHandler = "fallbackBlockHandler")
@GetMapping(value = "/consumer/fallback/{id}")
public CommentResult<Payment> order(@PathVariable Long id) {
CommentResult<Payment> result = restTemplate.getForObject(serverUrl + "/payment/" + id, CommentResult.class);
if (4L == id) {
throw new IllegalArgumentException("IllegalArgumentException 参数异常");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException 没有记录!");
}
return result;
}

public CommentResult<Payment> fallbackBlockHandler(Long id, BlockException e) {
Payment payment = new Payment(id, "null");
return new CommentResult(445, "限流,fallbackBlockHandler :" + e.getMessage(), payment);
}
}

然后设置个服务降级:

这个时候是效果是,当你在阈值以下请求的时候,会出现springboot的错误页面,因为触发了运行时异常;当你超过阈值触发了配置,那么fallbackBlockHandler就会接管,返回异常信息;

  1. fallback ,blockHandler 都配置,很明显他们是协同作战的。

准备测试项目整合 Feign

准备测试项目:

生产者同上面的项目,增加个消费者即可; 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>lichcloud</artifactId>
<groupId>cn.lichenghao.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>cloudalibaba-consumer-order85</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- 自定义通用 -->
<dependency>
<groupId>cn.lichenghao.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
</dependencies>

</project>

配置文件 application.xml

server:
port: 85
spring:
application:
name: cloudalibaba-consumer-order
cloud:
loadbalancer:
ribbon:
enabled: false
nacos:
discovery:
server-addr: 192.168.200.10:8848
sentinel:
transport:
dashboard: 192.168.200.10:8080
port: 8719
# 开启 Sentinel 对 openFeign 的支持
feign:
sentinel:
enabled: true

Feign客户端

package com.springcloudalibaba.service;

import cn.lichenghao.springcloud.entity.CommentResult;
import cn.lichenghao.springcloud.entity.Payment;
import com.springcloudalibaba.service.impl.PaymentServiceFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
* Payment客户端
*
* @author chenghao.li
*/
@FeignClient(value = "cloudalibaba-provider-server", fallback = PaymentServiceFallback.class)
public interface PaymentService {
@GetMapping(value = "/payment/{id}")
CommentResult<Payment> payment(@PathVariable("id") Long id);
}

兜底方法

package com.springcloudalibaba.service.impl;

import cn.lichenghao.springcloud.entity.CommentResult;
import cn.lichenghao.springcloud.entity.Payment;
import com.springcloudalibaba.service.PaymentService;
import org.springframework.stereotype.Component;

/**
* Payment客户端兜底方法
*
* @author chenghao.li
*/
@Component
public class PaymentServiceFallback implements PaymentService {
@Override
public CommentResult<Payment> payment(Long id) {
return new CommentResult<>(444, "服务降级返回,from PaymentServiceFallback", new Payment(id, null));
}
}

测试请求

package com.springcloudalibaba.controller;

import cn.lichenghao.springcloud.entity.CommentResult;
import cn.lichenghao.springcloud.entity.Payment;
import com.springcloudalibaba.service.PaymentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
* 测试 Sentinel Feign
*
* @author chenghao.li
*/
@RestController
public class ThirdController {

@Resource
private PaymentService paymentService;

@GetMapping(value = "/consumer/fallback2/{id}")
public CommentResult<Payment> order(@PathVariable("id") Long id) {
return paymentService.payment(id);
}
}

启动类

package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Order85 {
public static void main(String[] args) {
SpringApplication.run(Order85.class, args);
}
}

上面的代码是经过修改的,不然,会爆出很多的错误!!!!!!!!!!!!

报错1:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'thirdController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'com.springcloudalibaba.service.PaymentService': Requested bean is currently in creation: Is there an unresolvable circular reference?

报错2:  xx  parseAndValidateMetadata xx 方法调用的错误

报错3:No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc

解决:

  1. 版本兼容的问题

我使用的版本:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.12.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>

修改 spring-cloud-alibaba 版本为如下,解决报错1;

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<!--<version>2.1.0.RELEASE</version>-->
<version>2021.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>

参考官方issues:https://hub.nuaa.cf/alibaba/Sentinel/issues/2576  这个是镜像地址,打不开可以直接去官方的github 中搜索该 issue;

  1. 增加一个包,添加如下代码:

包:com.alibaba.cloud.sentinel.feign;解决报错2;原因见下面的注释;

package com.alibaba.cloud.sentinel.feign;

import feign.Contract;
import feign.MethodMetadata;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 在2.2.0.RELEASE里有一行注释描述,接口方法名拼写错误,在2.2.2.RELEASE方法已修正了,即方法名发生了改变。
* 在spring-cloud-alibaba-sentinel中的SentinelContractHolder类,用到了该接口的这个方法(feign2.2.0.RELEASE版本):
*/
public class SentinelContractHolder implements Contract {
private final Contract delegate;

/**
* map key is constructed by ClassFullName + configKey. configKey is constructed by
* {@link feign.Feign#configKey}
*/
public final static Map<String, MethodMetadata> METADATA_MAP = new HashMap<>();

public SentinelContractHolder(Contract delegate) {
this.delegate = delegate;
}

@Override
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
List<MethodMetadata> metadatas = delegate.parseAndValidateMetadata(targetType);
metadatas.forEach(metadata -> METADATA_MAP
.put(targetType.getName() + metadata.configKey(), metadata));
return metadatas;
}
}
  1. 修改配置文件及pom,解决报错3;

配置文件增加,

spring:
cloud:
loadbalancer:
ribbon:
enabled: false

pom文件,排除ribbon,增加 spring-cloud-starter-loadbalancer ; 该版本下已经放弃 ribbon;

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

参考资源:

https://mp.weixin.qq.com/s/Fvdj7aRYLwtzFE8kBSS8Hw