spring cloud alibaba使用

2023-11-10

文章目录

架构图

在这里插入图片描述

环境搭建

springboot和spring cloud alibaba版本有对应关系,具体:版本对应
这里使用
springboot:2.3.12.RELEASE
spring-cloud-alibaba:2.2.10-RC1
spring-cloud:Hoxton.SR12

父工程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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.chenke</groupId>
    <artifactId>spring-cloud-alibaba-tuling</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-cloud-alibaba-tuling</name>
    <description>spring-cloud-alibaba-tuling</description>

    <!--打包方式-->
    <packaging>pom</packaging>
    <properties>
        <java.version>1.8</java.version>
        <spring.cloud.alibaba.version>2.2.10-RC1</spring.cloud.alibaba.version>
        <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
        <spring.boot.version>2.3.12.RELEASE</spring.boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <!--子类使用,但是必须声明-->
    <dependencyManagement>
         <dependencies>
             <!--spring-cloud-alibab-->
             <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>
             <!--springboot-->
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-parent</artifactId>
                 <version>${spring.boot.version}</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
             <!--spring-cloud-->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-dependencies</artifactId>
                 <version>${spring.cloud.version}</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
         </dependencies>

    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

  • 打包方式修改为pom
  • 去掉paraent标签采用dependencyManagement标签管理。dependencyManagement管理的子类必须手动声明引用
  • properties 标签管理版本

Nacos

核心功能

  • 服务注册:Nacos Client会通过发送REST请求的方式向Nacos Server注册自己的服务,提供自身的元数据,比如ip地
    址、端口等信息。Nacos Server接收到注册请求后,就会把这些元数据信息存储在一个双层的内存Map中。
  • 服务心跳:在服务注册后,Nacos Client会维护一个定时心跳来持续通知Nacos Server,说明服务一直处于可用状态,防
    止被剔除。默认5s发送一次心跳。
  • 服务同步:Nacos Server集群之间会互相同步服务实例,用来保证服务信息的一致性。 leader raft
  • 服务发现:服务消费者(Nacos Client)在调用服务提供者的服务时,会发送一个REST请求给Nacos Server,获取上面
    注册的服务清单,并且缓存在Nacos Client本地,同时会在Nacos Client本地开启一个定时任务定时拉取服务端最新的注
    册表信息更新到本地缓存
  • 服务健康检查:Nacos Server会开启一个定时任务用来检查注册服务实例的健康情况,对于超过15s没有收到客户端心跳
    的实例会将它的healthy属性置为false(客户端服务发现时不会发现),如果某个实例超过30秒没有收到心跳,直接剔除该
    实例(被剔除的实例如果恢复发送心跳则会重新注册

下载以及配置

注册中心+配置中心+服务管理

nacos下载:nacos下载,这里用2.2.0 win版本

下载后解压,修改nacos\bin目录下startup.cmd中 set MODE=“standalone”
(默认为cluster集群,这里改为单机)
nacos\conf\application.properties 可以修改nacos的启动端口等信息,也可以设置数据源和mysql整合

双击startup.cmd启动,访问http://localhost:8848/nacos/#/login,账号密码都为nacos
在这里插入图片描述

测试使用

新建两个子模块,引入依赖order-nacos 和 stock-nacos,利用nacos实现order调用stock服务的接口
在这里插入图片描述
order-nacos 和 stock-nacos的pom

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
		<!-- nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

order-nacos 主要代码
要使用restTemplate来进行请求
必须加上@LoadBalanced,nacos自身并不具备服务名转地址的功能,需要这个注解。自带轮询的负载均衡算法

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
    {
        return restTemplateBuilder.build();
    }

配置类

server:
  port: 8010
spring:
  application:
    name: order-service
  cloud:
    nacos:
      #nacos地址
      server-addr: 127.0.0.1:8848
      #哪个用户的
      discovery:
        #哪个用户的
        username: nacos
        password: nacos
        #命名空间 默认public
        namespace: public

controller

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/getOrder")
    public String get()
    {
    	//这里使用服务名来调用,如果没有nacos就要写具体的ip地址,难以维护
        return restTemplate.getForObject("http://stock-service/stock/reduct",String.class);
    }
}

stock-nacos 主要代码

配置类除了服务名和端口同上一直,提供接口

@RestController
@RequestMapping("/stock")
public class StockController {

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

    @RequestMapping("/reduct")
    public String reduct()
    {
        return "hello,world" + port;
    }
}

在这里插入图片描述
启动两个stock,在order模块请求时会在客户端自动使用负载均衡算法,在两个stock中切换

界面一些功能

在这里插入图片描述
上面为大的分组,对应配置文件的namespace: public,适合不同项目时的管理,下面的分组名称适合项目内部的分类。

在这里插入图片描述
雪崩保护(nacos的不常用,一般用sentinel):
保护阈值: 设置0-1之间的值 0.6
临时实例: spring.cloud.nacos.discovery.ephemeral =false, 当服务宕机了也不会从服务列表中剔除

如果达到阈值,请求依然会发送到不健康状态的服务上,避免同时太多的请求到达健康的实例导致支撑不住

在这里插入图片描述
权重配合负载均衡机制

可配置项

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

nacos自带的ribbon负载均衡

  • Ribbon客户端组件提供一系列的完善的配置,如超时,重试等。通过Load Balancer获取到服务提供的所有机器实例,Ribbon会自动基于某种规则(轮询,随机)去调用这些服务。Ribbon也
    可以实现我们自己的负载均衡算法(从注册中心拉取列表,不用额外配置)
  • 服务端的负载均衡就类似于nginx,先发送请求,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;即在服务器端再进行负载均衡算法分配(要额外再nginx中配置服务的地址)

常用的轮询方法

  • 随机,通过随机选择服务进行执行,一般这种方式使用较少;
  • 轮训,负载均衡默认实现方式,请求来之后排队处理;
  • 加权轮训,通过对服务器性能的分型,给高配置,低负载的服务器分配更高的权重,均衡各个服务器的压力;
  • 地址Hash,通过客户端请求的地址的HASH值取模映射进行服务器调度。 ip —>hash
  • 最小链接数,即使请求均衡了,压力不一定会均衡,最小连接数法就是根据服务器的情况,比如请求积压数等参数,将请求分
    配到当前压力最小的服务器上。 最小活跃数

使用

	@Bean
	//这个就是ribbon的注解
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
    {
        return restTemplateBuilder.build();
    }

就可以用服务名替代ip地址进行访问了,而且有默认的负载均衡算法(轮询)

	@RequestMapping("/getOrder")
    public String get()
    {
        return restTemplate.getForObject("http://stock-service/stock/reduct",String.class);
    }

ribbon的负载均衡
在这里插入图片描述

  • RandomRule 随机
  • RoundRobinRule 轮询负载均衡策略
  • RetryRule 在轮询的基础上进行重试(在连接可用时间未超时中)
  • WeightedResponseTimeRule 权重 如果一个服务的平均响应时间越短则权重越大,那么该服务实例被选中执行任务的概率也就越大
  • BestAvailableRule 过滤掉失效的服务实例的功能,然后顺便找出并发请求最小的服务实例来使用(没有采用轮询)
  • ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器(没有采用轮询)
  • AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
  • NacosRule 基于nacos上的权重进行的负载均衡

配置负载均衡
1.java配置方法
在这里插入图片描述
config要放在springboot项目扫描不到的包中,不如不同的负载均衡算法会失效
RandomRuleConfig

@Bean
    public IRule getRule()
    {
    	
        return new RandomRule();
    }

WeightedResponseTimeRuleConfig

@Bean
    public IRule getRule()
    {
        return new WeightedResponseTimeRule();
    }

使用

@SpringBootApplication
//name是服务名(nacos上),多个@RibbonClient就是针对不同的服务用不同的算法
@RibbonClients(value = {
        @RibbonClient(name = "stock-service",configuration = RandomRuleConfig.class)
        //,@RibbonClient(name = "stock-xxx",configuration = WeightedResponseTimeRuleConfig.class)
})
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
    {
        return restTemplateBuilder.build();
    }
}

2.配置文件方式
采用nacos的权重,首先在nacos上配置服务的权重,或者在项目中配置。
spring.cloud.nacos.discovery.weight

客户端配置
在这里插入图片描述

stock-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

3.自定义负载均衡算法
实现抽象类AbstractLoadBalancerRule
Server choose(Object var1) 代表选择哪个服务
ILoadBalancer 表示从nacos上获取对应服务名的服务
在这里插入图片描述
默认都是懒加载,第一次调用才会加载可能会慢,可以修改配置

 ribbon:
   eager‐load:
     # 开启ribbon饥饿加载
     enabled: true
     # 配置mall‐user使用ribbon饥饿加载,多个使用逗号分隔
     clients: mall‐order

OpenFegin

Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不
到这是远程方法,更感知不到这是个 HTTP 请求。它像 Dubbo 一样,consumer 直接调用接
口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。它解决了
让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布
式环境开发。

引入依赖(客户端)

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

创建接口feign(客户端)

//服务名,path是类上的@RequestMapping,没有可不写
@FeignClient(value = "stock-service",path = "/stock")
public interface StockControllerFeign {

    @RequestMapping("/reduct")
    String reduct();
}

对应的服务上的实现类

@RestController
@RequestMapping("/stock")
public class StockController {
    @RequestMapping("/reduct")
    public String reduct()
    {
        return "hello,world" + port;
    }
}

springboot主方法上加上注解起开(创建的接口要可以被扫描到)

@EnableFeignClients

客户端调用服务端接口

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private StockControllerFeign stockControllerFeign;
    @RequestMapping("/getOrder")
    public String get()
    {
        return stockControllerFeign.reduct();
    }
}

日志配置

springboot的日志等级默认为info,先修改为debug

//该包名下
logging:
    level:
      com.chenke.order.feign: debug

配置文件形式(全局配置)

@Configuration
public class FeignLog {

    @Bean
    public Logger.Level feignLoggerLevel() {
         //设置日志等级
         return Logger.Level.FULL;
         }
}

配置文件形式(部分feign才有日志)

feign:
  client:
    config:
      stock-service: #对应微服务
        loggerLevel: FULL

配置类形式(部分feign才有日志)
去掉@Configuration

public class FeignLog {

    @Bean
    public Logger.Level feignLoggerLevel() {
         //设置日志等级
         return Logger.Level.FULL;
         }

}

在对应的feign的注解上添加configuration

@FeignClient(value = "stock-service",path = "/stock",configuration = FeignLog.class)

设置超时时间

feign:
  client:
    config:
      stock-service: #对应微服务
        loggerLevel: FULL
        connectTimeout: 5000 #连接超时时间,默认2s,A连接到B的时间
        readTimeout: 10000 #请求处理超时时间,默认5s,连接之后B处理的时间

配置文件,使用和上面日志的配置差不多

@Configuration
 public class FeignConfig {
 	 @Bean
 	public Request.Options options() {
 		return new Request.Options(5000, 10000);
 	}
 }

自定义拦截器

在fegin调用远程服务之前进行拦截处理(写在客户端)

public class MyInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        //业务逻辑
        System.out.println("自定义拦截器启动");
    }
}

注入方式(代码)

@Configuration
public class FeignLog {
	@Bean
     public MyInterceptor getMyInterceptor()
     {
         return new MyInterceptor();
     }
}

注入方式(配置文件)

feign:
  client:
    config:
      stock-service: #对应微服务
        loggerLevel: FULL
        connectTimeout: 5000 #连接超时时间,默认2s,A连接到B的时间
        readTimeout: 10000 #请求处理超时时间,默认5s,连接之后B处理的时间
        requestInterceptors[0]: com.chenke.order.config.MyInterceptor
        requestInterceptors[1]: com.chenke.order.config.MyInterceptor

注解模式和日志差不多

Nacos-config

官方文档
原理是在项目中,会有一个定时器,大概10ms拉取nacos上最新的MD5和本地的MD5做比较,如果不同就会进行跟新

如果要做权限管理,要开启nacos的配置文件中的

nacos.core.auth.caching.enabled=true

根据nacos上的配置文件获取值

引入依赖

 <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 </dependency>

在项目中必须引入一个bootstrap.properties,可以把nacos的配置都移动到这

# 必须和服务名相同
spring.application.name=order-service
spring.cloud.nacos.server-addr=127.0.0.1:8848
# 如果开启了权限要添加账号密码
spring.cloud.nacos.config.username=nacos
spring.cloud.nacos.config.password=nacos

在nacos上配置文件(默认data id要是服务名.properties)
在这里插入图片描述
在这里插入图片描述
使用

        String userName = applicationContext.getEnvironment().getProperty("user.name");
        String userAge = applicationContext.getEnvironment().getProperty("user.age");
        System.err.println("user name :"+userName+"; age: "+userAge);

使用yaml文件
这个配置的文件后缀只针对默认的配置文件(和服务同名)
bootstrap.properties 加上

# 默认是properties 
spring.cloud.nacos.config.file-extension=yaml

再把nacos上的data id改成 服务名+yaml

切换环境

只有默认的配置文件(data id相同的)才能用
在这里插入图片描述
使用这种格式,然后在bootstrap.properties添加

spring.profiles.active=dev

也可以在idea上直接配置启动
在这里插入图片描述

配置文件的优先级

spring.profiles.active=dev 如果dev不存在,还会使用默认的配置文件。如果dev中某个属性不存在,也会使用默认的配置文件中的值
dev

chen.name=ck

默认文件

chen.age=15

在spring.profiles.active=dev情况下 name和age都能获取到值

命名空间的使用

在这里插入图片描述

可以修改去那个空间获取配置文件(默认public)

spring.cloud.nacos.config.namespace=cc5458d0-77e1-4cd1-950a-291c402bac57

在这里插入图片描述
可以修改去哪个组获取配置文件(默认DEFAULT_GROUP)

spring.cloud.nacos.config.group=chenkeGroup

在这里插入图片描述

使用自定义的DataId配置

spring.cloud.nacos.config.extension-configs[n].data-id 的值必须带文件扩展名,文件扩展名既可支持 properties,又可以支持 yaml/yml。文件名字可以乱写,但是扩展名必须properties或者yaml/yml
在这里插入图片描述

spring.cloud.nacos.config.extension-configs[0].data-id=chenke.properties
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true

等价于

spring.cloud.nacos.config.shared-configs[0].data-id=chenke.properties
spring.cloud.nacos.config.shared-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.shared-configs[0].refresh=true

但是在文件中如果存在相同的key优先级有所不同,会根据优先级覆盖

profiles>默认>extension-configs(下标越大越优先)>shared-configs(下标越大越优先)

给实体类赋值

@Component
@RefreshScope
public class User {
    @Value("${user.name}")
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

@Value可以直接读取远程配置文件,加上@RefreshScope可以实时刷新远程的修改

sentinel

官网

所有降级方法都要加上参数BlockException ex

初体验

限流,每秒只能访问一次
导入依赖

<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.6</version>
</dependency>

代码形式

@RestController
@RequestMapping("/sentinel")
public class SentinelController {

    //等于一个方案名
    private static final String RESOURCE_NAME = "hello";
    @RequestMapping(value = "/hello")
    public String hello() {
        Entry entry = null;
        try {
            // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
            entry = SphU.entry(RESOURCE_NAME);
            // 被保护的业务逻辑
            return "hello";
        } catch (BlockException e) {
            // 资源访问阻止,被限流或被降级
             //进行相应的处理操作
            System.out.println("block");
        } catch (Exception ex) {
            // 若需要配置降级规则,需要通过这种方式记录业务异常
            Tracer.traceEntry(ex, entry);
        }
        finally {
            if (entry != null) {
                entry.exit();
            }
        }
        return "g";
    }
    /**
      * 定义流控规则 初始化bean的
      */
    @PostConstruct
    private static void initFlowRules() {
         List<FlowRule> rules = new ArrayList<>();
         FlowRule rule = new FlowRule();
         //设置受保护的资源
         rule.setResource(RESOURCE_NAME);
        // 设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // 一秒一次
        rule.setCount(1);
        rules.add(rule);
        // 加载配置好的规则
        FlowRuleManager.loadRules(rules);
    }
}

@SentinelResource注解的使用

详细使用官方
不仅仅可以针对controller,在业务方法上也可以设置
依赖

		<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.6</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.6</version>
        </dependency>

注入切面

@Configuration
public class SentinelConfig {
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
         return new SentinelResourceAspect();
    }
}

使用

@RestController
@RequestMapping("/sentinelAnn")
public class SentinelAnnController {

    //等于一个方案名
    private static final String SENTINEL_RESOURCE = "SentinelResource";
    @RequestMapping(value = "/hello")
    @SentinelResource(
            value = SENTINEL_RESOURCE,
            blockHandler  = "qpsHello",
            defaultFallback = "throwableHello1",
            fallback = "throwableHello"
             )
    public String hello() {
            int i = 1/0;
            return "hello";
    }
    public  String qpsHello(BlockException ex)
    {
        ex.printStackTrace();
        return "我被限流了呃";
    }

    public  String throwableHello(Throwable ex)
    {
        ex.printStackTrace();
        return "我异常了,贼炸";
    }
    public  String throwableHello1(Throwable ex)
    {
        ex.printStackTrace();
        return "我异常了,贼炸1";
    }
    /**
      * 定义流控规则 初始化bean的
      */
    @PostConstruct
    private static void initFlowRules() {
         List<FlowRule> rules = new ArrayList<>();
         FlowRule rule = new FlowRule();
         //设置受保护的资源
         rule.setResource(SENTINEL_RESOURCE);

        // 设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // 一秒一次
        rule.setCount(1);
        rules.add(rule);
        // 加载配置好的规则
        FlowRuleManager.loadRules(rules);
    }
    }

在这里插入图片描述
都属于BlockException
都属于BlockException

blockHandler 优先级大于fallback,比如限制了qps为1,但是代码会有算术异常。在多次访问的情况下走blockHandler 。 所有方法都必须为public

注解实现服务熔断降级

官方使用
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

例如:调用服务订单–>用户积分–>库存模块。这里的用户积分就属于弱模块,当积分模块出现问题,可以暂时降级为服务订单–>库存模块,积分模块在后期再进行补偿。

@RestController
@RequestMapping("/degrade")
public class DegradeController {
    //等于一个方案名
    private static final String SENTINEL_RESOURCE = "degrade";
    @RequestMapping(value = "/hello")
    @SentinelResource(
            value = SENTINEL_RESOURCE,
            blockHandler  = "deHello"
    )
    public String hello() {
        //模拟积分(弱依赖)模块出问题情况
        System.out.println("订单创建成功");
        System.out.println("积分调用成功"+1/0);
        System.out.println("库存调用成功");
        return "成功";
    }

    //降级后方法
    public String deHello(BlockException ex)
    {
        //舍弃积分(弱依赖)的调用
        System.out.println("订单创建成功");
        System.out.println("库存调用成功");
        return "成功";
    }

        @PostConstruct
        private static void initFlowRules() {
        List<DegradeRule> rules = new ArrayList<>();
        //再30秒内 最少有两次请求,且异常两次后走降级方法,10秒后恢复
            // 熔断恢复后 如果马上又异常,不会进行上面的判断,而是直接继续降级
            // count数会多一次,源码用的不是大于等于
        DegradeRule rule = new DegradeRule(SENTINEL_RESOURCE)
                .setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
                .setCount(2) //两次(实际三次)
                .setMinRequestAmount(2) //最少两次请求
                .setStatIntervalMs(30*1000) //30秒内
                .setTimeWindow(10);//熔断降级10秒
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
		//在每次状态变化的时候回调
		EventObserverRegistry.getInstance().addStateChangeObserver("logging",
                    (prevState, newState, rule1, snapshotValue) -> {
                        if (newState == CircuitBreaker.State.OPEN) {
                            // 变换至 OPEN state 时会携带触发时的值
                            System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
                                    TimeUtil.currentTimeMillis(), snapshotValue));
                        } else {
                            System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
                                    TimeUtil.currentTimeMillis()));
                        }
                    });
    }
}

控制台部署

非springboot springcloud环境

导入依赖

<dependency>
			<!--sentinel核心-->
         <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.6</version>
        </dependency>
<!--sentinel切面-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.6</version>
        </dependency>
<!--控制台-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.6</version>
        </dependency>

下载对应的控制台jar包
https://github.com/alibaba/Sentinel/releases

启动jar包,可以编辑成win批处理

java -Dserver.port=8858 -Dsentinel.dashboard.auth.username=chenke -Dsentinel.dashboard.auth.password=123456 -jar D:\huangjing\sentinel-dashboard-1.8.6.jar
pause

启动后在项目的jvm参数中添加

端口和上方客户端端口对应
-Dcsp.sentinel.dashboard.server=127.0.0.1:8858 

启动项目后访问接口,即可看到接口访问情况,以及用代码配置的策略
在这里插入图片描述
在这里插入图片描述

整合spring-cloud-alibab

官方文档

依赖

<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

项目配置文件添加,客户端的端口信息

spring:
  application:
    name: order-service
  cloud:
    nacos:
      #nacos地址
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858

控制台使用

统一异常处理

如果抛出的异常不需要做比较特殊的处理。可以设置统一的异常处理,在接口上就不需要写@SentinelResource注解了,但是这样就没有资源名了,直接根据接口路径配置即可
在这里插入图片描述
e.getRule 可以返回详细的控制规则

实时监控

在这里插入图片描述

簇点链路

在这里插入图片描述
可以看到所有的接口和配置的资源名 (配置规则要在资源名的那一行配置,这里是自定义的degrade)

流控规则

在这里插入图片描述
QPS:一秒内可以请求多少次(单机阈值),超过的请求抛出异常
并发线程数:针对慢sql等情况。同时允许多少个线程(单机阈值)同时执行。例如一个服务需要10秒才能进行响应,设置了单机阈值为1,只有在一个线程执行完10秒后返回,新的请求才能进入。

在这里插入图片描述
直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

例子(限制了每秒1次):
直接:该资源超过限制即触发
关联:例如资源名A为查询的功能,可以配置一个关联的路径B为关联资源(修改),用B来判断规则,如果达到限流A。因为修改和查询同时占用资源,但是修改优先度更高。
链路:可以配置路径,针对这些路径进行限流(没有配置的路径可以随便访问该资源)

关联

设置两个接口,和一个业务类。模拟查询和修改的情况

    @RequestMapping(value = "/get")
    public String hello() {
        return orderService.getName("查询");
    }
    @RequestMapping(value = "/update")
    public String hello1() {
        return orderService.getName("修改");
    }

配置
在这里插入图片描述
如果update达到了规则,则限制get的功能,update不受影响

限流的是get接口,而不是业务实现

链路

配置文件加上

spring.cloud.sentinel.web‐context‐unify: false

如果@SentinelResource写再业务方法上 ,无法通过BlockException异常的统一处理,只能自己编写方法

设置两个接口,和一个业务类。模拟查询和修改的情况

    @RequestMapping(value = "/get")
    public String hello() {
        return orderService.getName("查询");
    }
    @RequestMapping(value = "/update")
    public String hello1() {
        return orderService.getName("修改");
    }
@Service
//模拟业务调用数据库
public class orderService {
    @SentinelResource(value = "getName",blockHandler = "getNameDe")
    public String getName(String name)
    {
        System.out.println("调用数据库。。。。");
        return name;
    }

    public String getNameDe(String name, BlockException ex)
    {
        return "限流"+name;
    }
}

请求一次接口后查看控制台,会出现调用的链路
在这里插入图片描述
在簇点链路界面随便点击一个getName进行配置
在这里插入图片描述
点击新增后添加规则,然后在流控规则的页面就能看到配置。可以重复上面步骤配置多个链路。
在这里插入图片描述
把规则update的删除,就会发现,只有查询会被流控。而修改可以随便访问,限流的业务实现,而不是get或者update接口

流控效果

  • 快速失败 超过洪峰流量后直接拒绝
  • Warm up(激增流量:某一些时间点流量暴增,平缓流量->突然增加->平缓流量) 设置预热时间,在这时间内,慢慢的达到阈值。
  • 排队等候(脉冲流量:一段时间内流量暴增,平缓流量->突然增加->平缓流量->突然增加) 超过洪峰流量后在设置的时间内,如果前面的请求响应完,还在时间范围,就继续处理

例子

  • Warm up:qps设置成10000,预热时间为5秒。第一秒qps为(10000/3,默认因子为3)3333,慢慢的增加到10000,可以给系统增加缓存的时间。以免瞬间所有请求打到数据库(缓存击穿)
  • 排队等候:qps设置10000,超时等待时间设置成五秒。如果第一秒打进了20000,先处理其中的10000,保留10000,如果在5秒内,系统不繁忙了。再处理这10000。

熔断规则

  • 慢调用比例
    在这里插入图片描述

  • 异常比例
    在这里插入图片描述

  • 异常数
    在这里插入图片描述
    多作用于客户端

热点参数流控

  • 一定要使用@SentinelResource,统一异常处理没有办法针对热点key进行判断
  • 参数必须是long,int,double,float,char,byte,String
@RestController
@RequestMapping("/degrade")
public class DegradeController {

    @RequestMapping(value = "/get")
    @SentinelResource(value = "hot",blockHandler = "hotHello")
    public String hello(Integer id) {
        return "成功"+id;
    }
    
    public String hotHello(Integer id,BlockException ex) {
        return "限流了"+id;
    }
}

流控id为1的参数
在这里插入图片描述
测试结果:访问id为1的4次后进入了限流方法,而反问id为2需要11次。

单机阈值: 针对所有参数的值进行设置的一个公共的阈值

  1. 假设当前 参数 大部分的值都是热点流量, 单机阈值就是针对热点流量进行设置, 额外针对普通流量进行参数值流控
  2. 假设当前 参数 大部分的值都是普通流量, 单机阈值就是针对普通流量进行设置, 额外针对热点流量进行参数值流控

系统保护规则

属于兜底的保护规则,在不清楚什么原因,或者流量毫无规律的情况下设置全局的保护
在这里插入图片描述

在这里插入图片描述
是针对单台机器所有的平均值进行计算的

授权规则

集群流控

openFeign整合sentinel

在这里插入图片描述
在调用方也实现远程接口的实现,在@FeignClient的注解fallback后面添加

控制台规则持久化

默认控制台的配置没有持久化,重启就消失,这里使用nacos的配置中心来使用

导入依赖

<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

在nacos上编写配置文件
在这里插入图片描述
都对应规则的内容

[
    {
        "resource":"hot",
        "controlBehavior":0,
        "count":3.0,
        "grade":1,
        "limitApp":"default",
        "strategy":0
    }
]

在项目中添加配置文件

server:
  port: 8010
spring:
  application:
    name: order-service
  cloud:
    nacos:
      #nacos地址
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
    #sentinel配置~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858
      web-context-unify: false
      datasource:
        flow-rule: # 可以自定义
          nacos:
           server-addr: 127.0.0.1:8848
           username: nacos
           password: nacos
           dataId: sentinel.rule
           rule‐type: flow

重启项目即可。但是如果在sentinel上修改了配置并不会同步到nacos,需要手动同步(或者源码扩展)

Seata分布式事务

2PC
AT(Seata解决方案)
TCC
可靠消息最终一致性的方案 MQ

使用部署

官网下载地址

1.修改持久化配置,默认是file模式,存在本地。但是在集群模式下无法统一,改成db模式
conf/application.yml 下修改,并配置连接。再新建表(seata\script\server\db 文件地址)
在这里插入图片描述
在这里插入图片描述

2.seata也要注册到注册中心,要通过注册中心和服务来进行交互。配置文件
在这里插入图片描述
3.seata配置注册中心配置中心。(扩展配置)
在这里插入图片描述
seata\script\config-center\config.txt 这个文件需要部署到nacos的配置中心上,修改mode为db,并修改数据库相关配置

store.mode=db
store.lock.mode=db
store.session.mode=db
# 关于db的配置也要修改

4.文件中的service.vgroupMapping.default_tx_group=default 代表异地容灾
在这里插入图片描述
5.将这个txt配置文件同步到nacos
seata\script\config-center\nacos目录下的nacos-config.sh,无法运行安装一个git

sh nacos-config.sh -u nacos -w nacos

-h  ip地址 默认localhost
-p 端口 默认8848
-g 配置分组 默认SEATA_GROUP
-t 租户信息,默认为空,对应nacos命名空间id
-u 账号 如果nacos开启了权限
-p 密码 如果nacos 开启了权限

6.配置 @GlobalTransactional

两个模块,订单和库存

都添加依赖

<dependency>
 <groupId>com.alibaba.cloud</groupId>
 <artifactId>spring‐cloud‐starter‐alibaba‐seata</artifactId>
</dependency>

7.各微服务对应数据库中添加undo_log表(seata失败时的逆向sql)

CREATE TABLE `undo_log` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,
 `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
 `context` varchar(128) NOT NULL,
 `rollback_info` longblob NOT NULL,
 `log_status` int(11) NOT NULL,
 `log_created` datetime NOT NULL,
 `log_modified` datetime NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

8.修改application.yml配置
在这里插入图片描述

在这里插入图片描述
即可使用@GlobalTransactional

geteWay

初体验

1.新建模块gateway,并加入依赖(和mvc的依赖冲突)

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

2.修改application.yml配置

server:
  port: 8088
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
        - id: order_cyz
          uri: http://127.0.0.1:8011 #需要路由的路径
          predicates:
            - Path=/cyz/**  #断言,匹配路径
          filters:
            - StripPrefix=1 #过滤器,去掉第一层的请求

3.访问

http://127.0.0.1:8088/cyz/stock/reduct 等于访问  http://127.0.0.1:8011/stock/reduct

断言工厂

内置断言工厂

  • 基于Datetime类型的断言工厂
    AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
    BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
    BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
    时间格式:ZonedDateTime.now()
routes:
        - id: order_cyz
          uri: http://127.0.0.1:8011 #需要路由的路径
          predicates:
            ‐ After=2019‐12‐31T23:59:59.789+08:00[Asia/Shanghai] #在这个事件之前才能请求
            ‐ Before=2019‐12‐31T23:59:59.789+08:00[Asia/Shanghai] #在这个事件之后才能请求
            ‐ Between=2019‐12‐31T23:59:59.789+08:00[Asia/Shanghai],2019‐12‐31T23:59:59.789+08:00[Asia/Shanghai] #在这个事件之前才能请求
            
  • 基于远程地址的断言工厂
    RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中
‐ RemoteAddr=192.168.1.1/24
  • 基于Cookie的断言工厂
    CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求
    cookie是否具有给定名称且值与正则表达式匹配。
 ‐ Cookie=chocolate,ch
  • 基于Header的断言工厂
    HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。
 ‐ Header=X‐Request‐Id, \d+
  • 基于Host的断言工厂
    HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。
‐ Host=**.testhost.org
  • 基于Method请求方法的断言工厂
    MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
‐ Method=GET
  • 基于Path请求路径的断言工厂
    PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
 ‐ Path=/foo/{segment} #{}占位符 可以匹配reful风格
  • 基于Query请求参数的断言工厂
    QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。
‐ Query=baz, ba.    #xxx:8080?baz=1
  • 基于路由权重的断言工厂
    WeightRoutePredicateFactory:接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发
 routes:
   ‐id: weight_route1
  	 uri: host1
   	 predicates:
  		‐Path=/product/**
  		‐Weight=group3, 1
  ‐id: weight_route2
     uri: host2
     predicates:
  		‐Path=/product/**
  		‐Weight= group3, 9

自定义断言工厂

自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过
exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。
1、 必须spring组件 bean
2. 类必须加上RoutePredicateFactory作为结尾
3. 必须继承AbstractRoutePredicateFactory
4. 必须声明静态内部类 声明属性来接收 配置文件中对应的断言的信息
5. 需要结合shortcutFieldOrder进行绑定
6.通过apply进行逻辑判断 true就是匹配成功 false匹配失败

内置过滤器

第六点中全部都是
例如添加请求头

filters:
  ‐ AddRequestHeader=X‐Request‐color, red #添加请求头

自定义过滤器

继承AbstractNameValueGatewayFilterFactory且我们的自定义名称必须要以GatewayFilterFactory结尾并交给spring管理。

全局过滤器

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring cloud alibaba使用 的相关文章

随机推荐

  • Mysql -- 设置中国时区时间

    Mysql 设置中国时区时间 查看mysql的时区设置 mysql gt show variables like time zone 修改mysql的时区设置 注 mysql的默认时区是UTC 8 00是中国所在时区 东八区 mysql g
  • Leetcode 21. 合并两个有序链表

    Leetcode 21 合并两个有序链表 1 问题分析 2 问题解决 3 总结 1 问题分析 题目链接 https leetcode cn com problems merge two sorted lists 本质上就是一个链表操作问题
  • 解读CUDA Compiler Driver NVCC - Ch.3

    前言 上一篇文章简单了介绍了nvcc预定义的宏 以及支持的编译阶段 对应的输入文件后缀和输出文件的默认名 本篇文章了解CUDA源文件编译的整个workflow Overview CUDA编译的工作原理如下 输入程序经过设备编译编译预处理 编
  • HTTP的报文格式、GET和POST格式解析

    TTP报文是面向文本的 报文中的每一个字段都是一些ASCII码串 各个字段的长度是不确定的 HTTP有两类报文 请求报文和响应报文 请求报文 一个HTTP请求报文由请求行 request line 请求头部 header 空行和请求数据4个
  • JSON的下划线转驼峰,驼峰转下划线

    由于遇到了奇葩甲方 需要将数据格式转成下划线的格式 但是我们项目都是按照标准驼峰格式 所以写了个工具类来转换 不仅仅限于驼峰和下划线 根据需要传入 有没有大佬把这个递归改成迭代的 使用到的依赖 fastjon google的guava工具包
  • QT中代码设计和.ui文件设计的区别

    在面试中很多面试官经常会问到 ui和代码设计的区别 在网上一搜发现几乎没有人去解答这个问题 首先我们看一下一个简单的deamon 分别是代码实现和 ui实现 代码版 ui文件实现版 通过以上两种实现方式 不难发现 代码上的实现能够更精细 u
  • Navicat安装教程

    1 软件下载地址 点击下载 2 首先将下载后的文件解压到本地 3 右键选择以管理员身份运行navicat 15 0 64bit exe 4 然后点击下一步按钮 5 勾选我同意 然后点击下一步按钮 6 选择指定的安装目录 然后点击下一步按钮
  • micropython-SPI通讯

    micropython SPI通讯 1 什么是SPI 2 SPI通讯原理 3 Micropython中的SPI 4 ZTMR测试SPI 1 ZTMR中SPI引脚 2 ZTMRSPI自测 2 SPI 2板之间通讯测试 1 什么是SPI SPI
  • malloc底层原理实现

    使用过c语言的都知道malloc是一个动态分配内存的函数 还可以通过free释放内存空间 如果我们想分析一下malloc的源码 这其实不是一会就能看懂的 但是我们可以讨论一下malloc的简单实现 在这之前 我们先来看一下虚拟内存空间 虚拟
  • 错误until the update interval of nexus-releases has elapsed or updates are forced

    错误 until the update interval of nexus releases has elapsed or updates are forced 之前是先往nexues本地库里上传了jar文件 从文件系统里传的 而不是从ne
  • 解决Port 8080 is already in use

    前言 在运行项目的时候报错显示端口号已被占用 如下图 解决方法 第一步 win R打开 输入cmd进入命令窗口 第二步 输入netstat ano回车 找到对应的进程PID为14472 第三步 输入命令tasklist回车 找到对应的进程名
  • 面向对象和面向过程思想概述

    面向过程的思想去实现一个功能的步骤 首先要做什么 怎么做 最后我们再代码体现 一步一步去实现 而具体的每一步都需要我 们去实现和操作 这些步骤相互调用和协作 实现我们的功能 每一个步骤我们都是参与者 并且 需要面对具体的每一个步骤和过程 这
  • 猿人学2023比赛题1~7题解之第一题

    前言 我从不回头看之我跟77的雨后小故事 这题有两个解法 分别是全局扣和找加密魔改点套库 方法一 全局扣 1 加密位置 2 确保在浏览器出值跟浏览器一样 1 先把全部代码拉下来 整体运行 发现会缺东西 这是发包的 直接删了就好 2 然后加密
  • mysql联合for update查询_sql的for update

    欢迎大家吐槽 oracle行级共享锁 通常是通过select from for update语句添加的 同时该方法也是我们用来手工锁定某些记录的主要方法 比如 当我们在查询某些记录的过程中 不希望其他用户对查询的记录进行更新操作 则可以发出
  • 【导航】RT-Thread 学习专栏目录 【快速跳转】

    本文是 矜辰所致 的 RT Thread 记录专栏的内容导航 结合自己的学习应用过程的总结记录 有基础理论 有与FreeRTOS的比较 有实际项目 有应用总结 目录 前言 一 环境篇 二 内核篇 三 设备和驱动篇 四 组件软件包篇 五 应用
  • [异步][jms][activeMq]如何做到重试机制不会导致一条消息被多次执行.

    淘宝海量存储之单机事务面临的问题及解决办法 http blog csdn net jiao fuyou article details 15499261 这篇文章讲的比较好 核心关键词 幂等 Message Queue ActiveMQ r
  • 前端HTML鼠标经过链接变换背景颜色

  • Win10关闭自带键盘的三种方法--亲测第三中命令方式有效(需要重启)

    Win10笔记本关闭自带键盘的方法 方法一 1 在Windows10系统桌面 右键点击桌面上的 此电脑 图标 在弹出菜单中选择 属性 菜单项 2 在打开的Windows系统属性窗口中 点击左侧边栏的 设备管理器 菜单项 3 这时会打开设备管
  • 二叉树及其遍历

    二叉树的定义 二叉二叉顾名思义 二叉树是每个节点最多有两个子树的树结构 二叉树的存储 二叉树的存储分为顺序存储和链式存储 顺序存储 深度为k的二叉树需要预留2 k 1 个存储单元 按编号顺序存储 遇空节点留空位 可以看到上面特别多的空节点
  • spring cloud alibaba使用

    文章目录 架构图 环境搭建 Nacos 下载以及配置 测试使用 界面一些功能 可配置项 nacos自带的ribbon负载均衡 OpenFegin 日志配置 设置超时时间 自定义拦截器 Nacos config 根据nacos上的配置文件获取