spring cloud alibaba 组件小结

本文详细介绍了Spring Cloud Alibaba的多个组件,包括Nacos(服务发现、配置管理)、Sentinel(流量控制、熔断降级)、Seata(分布式事务)等,以及如何在实际项目中使用它们,如配置中心、服务调用、负载均衡和网关等。通过实例演示了如何集成和配置这些组件,便于读者理解与实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringCloudAlibaba

简介:

  • 阿里巴巴提供的微服务开发一站式解决方案,是阿里巴巴开源中间件与 Spring Cloud 体系的融合;
  • 依托 Spring Cloud Alibaba,只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统;

组件:

  • img

开源组件

    • Nacos:发现、配置和管理微服务,相当于 Eureka/Consule + Config + Admin;

    • Dubbo

      • Java RPC,远程服务调用,相当于 Ribbon + Feign;
      • 使用 @DubboTransported 注解可将底层的 Rest 协议无缝切换成 Dubbo RPC 协议,进行 RPC 调用;
    • Sentinel

      • 限流、降级、熔断等,相当于 Hystrix + Dashboard + Turbine;
      • 默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入;
      • 支持查看限流降级 Metrics 监控;
    • Seata

      • 分布式事务,使用 @GlobalTransactional 注解,在微服务中传递事务上下文,可以对业务零侵入地解决分布式事务问题;
    • RocketMQ

      • 分布式消息系统,相当于 RabbitMQ;
      • 仓库地址:https://github.com/apache/rocketmq;
      • 各种插件地址:https://github.com/apache/rocketmq-externals;

商业组件

    • Alibaba Cloud ACM:配置中心;
    • Alibaba Cloud OSS: Object Storage Service,阿里云对象存储服务;
    • Alibaba Cloud SchedulerX: 任务调度,相当于 Quartz;
    • Alibaba Cloud SMS: 覆盖全球的短信服务;

--------------------------------------

Nacos

介绍:

  • Nacos 致力于帮助您发现、配置和管理微服务;

  • Service 是 Nacos 世界的一等公民,支持几乎所有主流类型的服务:

    • Kubernetes Service
    • gRPC & Dubbo RPC Service
    • Spring Cloud RESTful Service
  • 特性

    • 服务发现和服务健康监测;
    • 动态服务配置;
    • 动态 DNS 服务;
    • 服务及元数据管理;
  • 地图

    • img
  • 资料

    • 源码地址:https://github.com/alibaba/nacos.git
    • 历史版本:https://github.com/alibaba/nacos/releases
    • 文档地址:https://nacos.io/zh-cn/index.html
  • 依赖

    • 64 位 JDK 1.8+;
    • Maven 3.2.x+;
  • 安装

    • Windows

      • 从历史版本中下载 Zip 包,解压到本地即可使用;

运行:

  • Windows

    • startup.cmd -m standalone ---- 开启服务,默认为集群方式启动,启动报错,需改为单机版方式 standalone;
      shutdown.cmd ---- 关闭服务;
      
  • Linux

    • cd /usr/nacos/bin
    • sh startup.sh -m standalone ---- 开启服务,standalone 单机运行模式;
    • bash startup.sh -m standalone ---- Ubuntu 开启服务;
    • sh shutdown.sh ---- 关闭服务;
  • 访问主页:http://127.0.0.1:8848/nacos/

  • 应用

    • 服务管理

      • 服务注册

        • curl -X POST “http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=springBoot&ip=127.0.0.1&port=80”
      • 服务发现

        • curl -X GET “http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=springBoot”
    • 配置管理

      • 发布配置

        • curl -X POST “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld”
      • 获取配置

        • curl -X GET “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test”
    • 命名空间

      • 用于区分不同的部署环境,实现隔离,不同的命名空间逻辑上是隔离的,其主要作用是区分服务使用的范围,比如开发、测试、生产、灰度四个命名空间来互相隔离;
      • img

--------------------------------------

Parent Project

父工程:

      • Spring Boot 版本: 2.6.3;
      • Spring Cloud 版本:Spring Cloud 2021.0.1;
      • Spring Cloud Alibaba 版本:2021.0.1.0;
    • 搭建 Maven Java 项目

      • 参考 Tool_IDE 创建 java_spring_cloud_alibaba;
      • 删除 src,项目右键 properties ---- Java Build Path ---- Source,删除 Source 包;
    • Pom 依赖

      • 指定打包类型:

        <packaging>pom</packaging>
        

父工程pom.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sfac</groupId>
    <artifactId>spring_cloud_alibaba</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring_cloud_alibaba_entity</module>
    </modules>

    <name>spring_cloud_alibaba</name>
    <packaging>pom</packaging>
    <url>http://www.example.com</url>


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <spring.boot.version>2.6.3</spring.boot.version>
        <spring.cloud.version>2021.0.1</spring.cloud.version>
        <spring.cloud.alibaba.version>2021.0.1.0</spring.cloud.alibaba.version>
    </properties>

    <!-- 父工程版本管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <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>



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

        <!-- Apache 工具组件 -->
        <!-- 字符串、对象、日期等工具包 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- 摘要运算、编码 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        <!-- IO -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>

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

    <build>

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

随即clean,install打包

注意打包时的坑:

Unable to find a single main class

spring-boot-maven-plugin 这个插件,会去找程序入口,先去查找带 @SpringBootApplication 注解的类,项目中没有,就去查找 main 方法,当项目中有一个以上的 main 方法的时候,这货就懵逼了,到底和哪个妹子在一起呢?于是抛出了上面的错误;
解决方案一
在 spring-boot-maven-plugin 插件中配置 mainClass 属性,指定入口类;

<configuration>
    <mainClass>***</mainClass>
</configuration>

解决方案二
如果打包的项目是继承至父类,那么方案一不适合,需要配置 start-class 属性

在父工程中:

<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
</plugins>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
      <start-class>com.sfac.App</start-class>
  </properties>

方案三
项目里只留一个 main 方法,其余的干掉,并不推荐这么做;

在子模块中:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <classifier>exec</classifier>
  </configuration>
</plugin>

在父工程中创建EntityModule的Maven项目

将微服务中使用的entity抽取出去,和SpringCloud差不多

子Module的pom.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.sfac</groupId>
  <artifactId>spring_cloud_alibaba_entity</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>spring_cloud_alibaba_entity</name>
  <url>http://www.example.com</url>
  <packaging>jar</packaging>

  <parent>
    <groupId>com.sfac</groupId>
    <artifactId>spring_cloud_alibaba</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
      <start-class>com.sfac.App</start-class>
  </properties>



  <dependencies>

    <!-- servlet -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

    <!-- javax.persistence -->
    <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>javax.persistence-api</artifactId>
      <version>2.2</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <classifier>exec</classifier>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

随即clean,install打包

在父工程中创建TestMoudle的SpringBoot项目

pom.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.sfac</groupId>
  <artifactId>spring_cloud_alibaba_entity</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>spring_cloud_alibaba_entity</name>
  <url>http://www.example.com</url>
  <packaging>jar</packaging>

  <parent>
    <groupId>com.sfac</groupId>
    <artifactId>spring_cloud_alibaba</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
      <start-class>com.sfac.App</start-class>
  </properties>



  <dependencies>

    <!-- servlet -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

    <!-- javax.persistence -->
    <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>javax.persistence-api</artifactId>
      <version>2.2</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <classifier>exec</classifier>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

在启动类上添加注解@EnableDiscoveryClient

@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudAlibabaTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAlibabaTestApplication.class, args);
    }

}

随即在父工程进行clean,install打包

在父工程中创建AccountMoudle的SpringBoot项目

pom.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>com.sfac</groupId>
        <artifactId>spring_cloud_alibaba</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>


    <groupId>com.sfac</groupId>
    <artifactId>spring_cloud_alibaba_account</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring_cloud_alibaba_account</name>
    <packaging>jar</packaging>
    <description>spring_cloud_alibaba_account</description>


    <properties>
        <java.version>1.8</java.version>
    </properties>


    <dependencies>
        <!--pagehelper-spring-boot-starter -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!--         mybatis-spring-boot-starter-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

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

        <!-- entity -->
        <dependency>
            <groupId>com.sfac</groupId>
            <artifactId>spring_cloud_alibaba_entity</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

在启动类上添加注解@EnableDiscoveryClient

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

@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudAlibabaAccountApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAlibabaAccountApplication.class, args);
    }

}

进行拆解后,随即在父工程进行clean,install打包

----------------------------------------

Nacos配置中心

说明:

  • Nacos 除了微服务的注册与发现之外,还将配置中心整合在了一起,我们可以将整个架构体系内的所有配置都集中在 Nacos 中存储;
  • 我们将改造微服务 Service Module Test 和 Service Module Account;

在test模块引入依赖:

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


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

然后创建配置文件bootstrap.properties,并将之前的application.properties改名applicationBackup.properties

保留test的properties配置,抽取出去公共的配置

# for server
server.port=8762

# for bootstrap
spring.cloud.bootstrap.enabled=true

# for application
spring.application.name=spring-cloud-alibaba-test
spring.profiles.active=dev

# for nacos discovery
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

# for nacos config
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.file-extension=properties

Nacos 主页创建微服务配置(详情见老师笔记)

  • http://127.0.0.1:8848/nacos

  • 配置服务 ---- 配置列表 ---- 新建配置;

  • Data ID:prefix−{prefix}-prefix{spring.profiles.active}.${file-extension}

    • ${prefix} ---- 默认 spring.application.name,也可通过 spring.cloud.nacos.config.prefix 配置;
    • spring.profiles.active−−−−环境,通过spring.profiles.active配置,若不配置,则没有−{spring.profiles.active} ---- 环境,通过 spring.profiles.active 配置,若不配置,则没有 -spring.profiles.active环境,通过spring.profiles.active配置,若不配置,则没有{spring.profiles.active} 这部分;
    • ${file-extension} ---- 文件后缀,通过 spring.cloud.nacos.config.file-extension 配置;
        • Group:暂时使用默认;
        • img
        • img

-----------------------------------------

服务调用

说明:

  • Service Module Account 中的 User 接口调用 Service Module Test 中的 City 接口,实现微服务接口调用;

  • 注册中心无论使用 Eureka Server 还是使用 Nacos,对应用层是没有影响的,这归功于 Spring Cloud Common 的封装,它在服务的注册与发现、客户端负载均衡等方面做了很好的抽象,具体实现由各厂商的中间件完成,应用层依赖于这些接口,不会关注具体的实现,就好比于 JDBC 接口,具体由什么数据库实现,应用层并不关心;

使用OpenFeign

account引入依赖

引入依赖:

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


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

在配置类上添加注解

@EnableFeignClients

import com.sfac.springCloudAlibabaAccount.config.CustomLoadBalancerConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//这个
@LoadBalancerClient(name = "spring-cloud-alibaba-test",
        configuration = CustomLoadBalancerConfig.class)
public class SpringCloudAlibabaAccountApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAlibabaAccountApplication.class, args);
    }

}

在service包下创建OpenFeignTest接口

用于调用 Service Module Test 微服务接口

import com.sfac.test.City;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "spring-cloud-alibaba-test")//注意这个注解,调用谁写谁
public interface OpenFeignTest {
    /**
      * 127.0.0.1/api/city/2234  -----get
     */
    @GetMapping("/api/test/city/{cityId}")
    public City getCityByCityId(@PathVariable int cityId);


}

最后再serviceImpl修改相关代码即可

   
   //首先引入这个接口
   @Autowired
    private OpenFeignTest openFeignTest;



@Override
public UserVo getUserVoById(int userId, int cityId) {
    UserVo userVo = new UserVo();
    User user = userDao.selectUserById(userId);
    BeanUtils.copyProperties(user, userVo);
    City city = openFeignTest.getCityByCityId(cityId);//调用即可
    userVo.setCity(city);
    
    return userVo;
}

----------------------------------

负载均衡Loadbalancer

在account模块引入依赖

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


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

这样配置后,访问策略是轮询

可以添加配置类,改为随机访问

CustomLoadBalancerConfig:

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

/**
 * 构造一个随机策略的负载均衡器
 */
public class CustomLoadBalancerConfig {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        // 在此也可返回自定义负载均衡器
        return new RandomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }

}

在启动类上加入注解@LoadBalancerClient

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@LoadBalancerClient(name = "spring-cloud-alibaba-test", 
        configuration = CustomLoadBalancerConfig.class)//这个,如果是轮询,把后面的去掉
public class SpringCloudAlibabaAccountApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAlibabaAccountApplication.class, args);
    }

}

最后打包两个不同端口号test模块,java -jar 命令运行之,然后测试即可

-----------------------------------------

GateWay网关

创建一个SpringBoot子模块

spring_cloud_alibaba_gateway

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>


    <parent>
        <groupId>com.sfac</groupId>
        <artifactId>spring_cloud_alibaba</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>


    <groupId>com.hqyj</groupId>
    <artifactId>spring_cloud_alibaba_gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring_cloud_alibaba_gateway</name>
    <description>spring_cloud_alibaba_gateway</description>


    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2021.0.4</spring-cloud.version>
    </properties>


    <dependencies>

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

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

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


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

    </dependencies>


    <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>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties:

# for server
server.port=8888

# for application
spring.application.name=spring-cloud-alibaba-gateway

# for nacos discovery
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

# for gateway route
spring.cloud.gateway.routes[0].id=testServer
spring.cloud.gateway.routes[0].uri=lb://spring-cloud-alibaba-test
spring.cloud.gateway.routes[0].predicates[0]=Path=/api/test/**

spring.cloud.gateway.routes[1].id=accountServer
spring.cloud.gateway.routes[1].uri=lb://spring-cloud-alibaba-account
spring.cloud.gateway.routes[1].predicates[0]=Path=/api/account/**

spring.main.web-application-type=reactive

配置跨域的配置类:

CorsAutoConfiguration:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

@Configuration
public class CorsAutoConfiguration {
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, request.getHeaders().getOrigin());
                // 允许的 header

                //允许跨域访问
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
                        "X-Token,Token,Authorization,x-requested-with,Content-Type");
                //允许的请求方式
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "PUT,POST, GET, OPTIONS, DELETE");
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

在启动类上添加注解:

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 SpringCloudAlibabaGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAlibabaGatewayApplication.class, args);
    }

}

同样clean,install打包测试:

http://127.0.0.1:8888/api/account/userVo/1/1890

和桌面上的index.html,发起ajax进行测试即可

--------------------------------------

Sentinel:监控、熔断、流控等

简介

  • 主要特性

    • img
  • 两大部分

    • 核心库(Java 客户端):不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持;
    • 控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器;
  • 文档地址:https://github.com/alibaba/Sentinel/wiki/介绍;

  • 仓库地址:https://github.com/alibaba/Sentinel;

安装与运行

  • 历史版本:https://github.com/alibaba/Sentinel/releases;

  • 下载到本地,CMD 运行

    • 默认 8080 端口运行,可能与其它软件冲突,故选择 9090 端口;
    • java -jar sentinel-dashboard-1.8.3.jar --server.port=9090
  • 访问:127.0.0.1:9090 sentinel | sentinel;

    • img

导入依赖:

在test和account模块添加依赖

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

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

在Nacos的配置中心修改配置:

test配置了配置中心,在配置中心修改

account没有,则在application.properties修改

# for sentinel
spring.cloud.sentinel.transport.dashboard=127.0.0.1:9090
spring.cloud.sentinel.transport.port=8719
management.endpoints.web.exposure.include=*

然后进行clean,install打包测试

测试各个接口,然后在Sentinel主页进行查看

http://127.0.0.1:9090/

实时监控

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9BpqgXw-1665109300334)(C:\Users\张大帅哥\AppData\Roaming\Typora\typora-user-images\image-20220929161510412.png)]

簇点链路

添加流控、熔断规则

详情见老师笔记

流量控制
  • 说明

    • 流量控制(Flow Control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性;
  • Service Module Account 实现

    • 对应微服务或接口上添加流控;

      • img
      • img
    • /api/user/{id},当每秒请求的次数超过阈值,那么会直接返回失败的信息;

    • 浏览器快速刷新 http://127.0.0.1:8004/api/user/1,得到被流控的结果;

      • img
熔断降级
  • 说明

    • 服务调用中,如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用方的响应时间也会变长,线程会产生堆积,最终可能耗尽线程池,服务本身也变得不可用,Sentinel 在服务出现不稳定情况时,会对让请求快速失败,避免影响到其他资源而导致级联错误,当资源被降级后,在接下来的时间窗口内,对该资源的调用都自动熔断;

    • 降级策略

      • 慢调用比例

        • img
        • 在 1000ms 内请求数超过 5 个,且平均响应时间超过 300ms 的请求的比例(超过 300ms 的请求占总请求的比例)大于 0.4,则该资源自动熔断 10s,10s 后根据下一个请求判断是否再次被熔断;
      • 异常比例

        • img
        • 在 1000ms 内请求数超过 5 个,且异常的比例(异常的请求占总请求的比例)大于 0.8,则该资源自动熔断 15s,15s 后根据下一个请求判断是否再次被熔断;
      • 异常数

        • img
        • 在 1000ms 内请求数超过 5 个,且异常的请求超过 6 个,那么该资源将自动熔断 20s,20s 后根据下一个请求判断是否再次被熔断;
实现:

在test的CityServiceImpl里面添加下面的代码:

@Override
@Transactional
public City getCityByCityId(int cityId) {
    System.out.println("===============" + port + "===============");
    if (cityId <= 0){//这里
        int i = 1/0;
    }
    return cityDao.getCityByCityId(cityId);
}

然后在account的调用上面方法的方法上添加注解:@SentinelResource

@Override
@SentinelResource(value = "getCityByCityId",//指定一个标识
        blockHandler = "blockHandler",//指定流控的方法名称
        fallback = "fallback" )//指定熔断的方法名称
public UserVo getUserVoById(int userId, int cityId) {
		...
}

然后写流控的熔断的方法,返回值必须和该方法一样:

    @Override
    @SentinelResource(value = "getCityByCityId",//指定一个标识
            blockHandler = "blockHandler",//指定流控的方法名称
            fallback = "fallback" )//指定熔断的方法名称
    public UserVo getUserVoById(int userId, int cityId) {
        UserVo userVo = new UserVo();
        User user = userDao.selectUserById(userId);
        BeanUtils.copyProperties(user, userVo);
        City city = openFeignTest.getCityByCityId(cityId);
        userVo.setCity(city);

        return userVo;
    }

    @Override
    @Transactional
    public Result<UserVo> updateUserVo(UserVo userVo) {
        openFeignTest.updateCity(userVo.getCity());

        if (userVo.getUserId() < 0){
            int i = 1/0;
        }
        User user = new User();
        BeanUtils.copyProperties(userVo,user);
        userDao.updateUser(user);
        return new Result<>(Result.ResultStatus.SUCCESS.code,
                "Update success",
                userVo);

    }


    /**
     * 流控或降级异常处理逻辑
     */
    public UserVo blockHandler(int userId, int cityId, BlockException exception) {
        if (exception instanceof FlowException) {//流控的exception
            System.out.println("您被限流了.");
        } else if (exception instanceof DegradeException) {//降级的exception
            System.out.println("您被降级了.");
        } else {
            System.out.println("City 接口不可用.");
        }
        return new UserVo();
    }
        /**
         * 非流控或降级异常处理逻辑(熔断)
         */
    public UserVo fallback(int userId, int cityId) {
        System.out.println("发生了非流控、降级异常,被熔断了.");
        return new UserVo();
    }
测试:

http://127.0.0.1:8888/api/account/userVo/-1/1890

------------------------------

Seata分布式事务

简介:

  • Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务;

  • 资料地址

    • Seata 项目 Github 地址:https://github.com/seata/seata
    • Seata 中间件下载地址:https://github.com/seata/seata/releases
    • Seata 中文官方文档:http://seata.io/zh-cn/
    • Seata 官方示例:https://github.com/seata/seata-samples

术语:

    • XID(Transaction ID):全局唯一的事务 ID;
    • TC (Transaction Coordinator):事务协调者,维护全局和分支事务的状态,驱动全局事务提交或回滚;
    • TM (Transaction Manager):事务管理器,定义全局事务的范围,开始全局事务、提交或回滚全局事务;
    • RM (Resource Manager):资源管理器,管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚;
  • 处理过程

    • TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID;
    • XID 在微服务调用链路的上下文中传播;
    • RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖;
    • TM 向 TC 发起针 XID 的全局提交或回滚决议;
    • TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求;
    • img

分支事务:只能管当前微服务,相当于@Transactional

协调者:管所有微服务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值