SpringCloud分布式微服务,整合动态服务发现、配置和服务管理平台、熔断降级、分布式事务、网关、远程调用和负载均衡、MybatisPlus访问数据库一整套解决方案

微服务示例

用例

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:

  • 仓储服务:对给定的商品扣除仓储数量。
  • 订单服务:根据采购需求创建订单。
  • 帐户服务:从用户帐户中扣除余额。

架构图

在这里插入图片描述

父工程搭建

创建一个SpringBoot工程,只留下pom.xml文件,并把依赖删除。
在这里插入图片描述
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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>vip.buddha</groupId>
    <artifactId>shopping</artifactId>
    <version>1.0.0</version>
    <name>shopping</name>
    <description>shopping project</description>

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

    <dependencies>

    </dependencies>

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

子工程搭建

根据用例创建仓储服务、订单服务、账户服务
在这里插入图片描述

storage服务

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">
    <parent>
        <artifactId>shopping</artifactId>
        <groupId>vip.buddha</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shopping-storage7001</artifactId>

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

application.yml文件

server:
  port: 7001

spring:
  application:
    name: shopping-storage

StorageMain7001主启动类

package vip.buddha;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

StorageController服务接口

package vip.buddha.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/storage")
public class StorageController {
    @RequestMapping("list")
    public String list() {
        return "this is storage list api";
    }
}

order服务

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">
    <parent>
        <artifactId>shopping</artifactId>
        <groupId>vip.buddha</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shopping-order8001</artifactId>

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

application.yml文件

server:
  port: 8001

spring:
  application:
    name: shopping-order

OrderMain8001主启动类

package vip.buddha;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

OrderController服务接口

package vip.buddha.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
public class OrderController {
    @RequestMapping("list")
    public String list() {
        return "this is order list api";
    }
}

account服务

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">
    <parent>
        <artifactId>shopping</artifactId>
        <groupId>vip.buddha</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shopping-account9001</artifactId>

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

application.yml文件

server:
  port: 9001

spring:
  application:
    name: shopping-account

AccountMain9001主启动类

package vip.buddha;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

AccountController服务接口

package vip.buddha.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/account")
@RestController
public class AccountController {
    @RequestMapping("list")
    public String list() {
        return "this is account list api";
    }
}

三个服务已经建好,传统的做法就是订单服务直接调用仓储服务和账户服务。但是直接调用存在的问题,所以得把服务放到注册中心去。

Nacos服务端搭建

Nacos服务端扮演的就是服务注册中心、服务提供者、服务消费者中的服务注册中心。
nacos挂网:https://nacos.io/zh-cn/
nacos代码仓库:https://github.com/alibaba/nacos
在这里插入图片描述
微服务技术整合,各技术存在不同版本问题。根据alibaba/spring-cloud-alibaba版本说明,选择了比较新的技术版本

SpringCloudAlibabaSpringCloudSpringBootNacosSeataSentinel
2021.0.1.02021.0.12.7.31.4.21.4.21.8.3

在这里插入图片描述
下载解压后,如上图所示。cmd进入bin目录,然后执行命令:startup.cmd -m standalone
在这里插入图片描述
出现上图,说明nacos服务端已启动,根据其网址进行登录,账号和密码默认都是nacos
在这里插入图片描述
在这里插入图片描述

服务注册

A调用B,B就是A的服务提供者,得把B服务注册到注册中心;B调用A,A就是B的服务提供者,得把A服务注册到注册中心。
要把服务注册到注册中心,服务就集成了nacos的客户端,同时应该有一个配置连接到Nacos的服务端。
父pom.xml文件加入如下内容:

<dependencyManagement>
    <dependencies>
        <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>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>

子application.yml配置里添加配置内容:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

启动服务后,服务提供者都注册进注册中心
在这里插入图片描述

服务调用

用户购买商品的业务逻辑,就是订单服务调用账户服务和仓储服务。
父pom.xml加入如下内容:

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

服务消费者,也就是shopping-order8001的pom.xml加入如下内容:

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

新增ServiceConfig配置类

package vip.buddha.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 ServiceConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

OrderController改成如下:

package vip.buddha.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@RequestMapping("/order")
public class OrderController {
    @Resource
    private RestTemplate restTemplate;

    private final String ACCOUNT_URL = "http://shopping-account";

    private final String STORAGE_URL = "http://shopping-storage";

    @RequestMapping("list")
    public String list() {
        String s1 = restTemplate.getForObject(ACCOUNT_URL + "/account/list", String.class);
        String s2 = restTemplate.getForObject(STORAGE_URL + "/storage/list", String.class);
        System.out.println(s1 + "," + s2);
        return "this is order list api";
    }
}

启动服务后,实现了远程调用
在这里插入图片描述
服务提供者负载均衡
A调用B,B服务处理业务逻辑耗时,则完成整个请求的瓶颈在B服务。
在这里新增一个仓储服务,实现仓储服务的负载均衡。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

配置中心

在开发运维过程中,存在多个环境,开发环境、测试环境、验收环境及生产环境,会连接不同的mysql、redis等。
在这里插入图片描述
在这里插入图片描述
父pom.xml添加以下内容:

<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    <!-- bootstrap 集成配置中心需要用bootstrap 配置文件-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
        <version>3.0.0</version>
    </dependency>
</dependencies>

子工程application.yml改成bootstrap.yml,内容都改成如下:

server:
  port: xxxx
spring:
  profiles:
    active: dev
  application:
    name: shopping-xxxx
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: e122716d-7502-4505-9472-c73900e4aefd
        group: dev
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        refresh-enabled: true
        namespace: e122716d-7502-4505-9472-c73900e4aefd
        group: dev

重写服务调用

上面有实现用户购买商品的业务逻辑,就是订单服务调用账户服务和仓储服务。但是代码并不优雅,后期如果有修改,可能存在到一个个接口去改。
可以把上面实现服务调用的所有代码去掉,这里重新实现。
父pom.xml加入如下内容:

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

服务消费者,也就是shopping-order8001的pom.xml加入如下内容:

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

OrderMain8001主启动类添加注解@EnableFeignClients
在这里插入图片描述
AccountService接口代码:

package vip.buddha.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

@Component
@FeignClient(value = "shopping-account")
public interface AccountService {
    @RequestMapping("/account/list")
    public String list();
}

StorageService接口代码:

package vip.buddha.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

@Component
@FeignClient(value = "shopping-storage")
public interface StorageService {
    @RequestMapping("/storage/list")
    public String list();
}

OrderController接口代码:

package vip.buddha.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.buddha.feign.AccountService;
import vip.buddha.feign.StorageService;

import javax.annotation.Resource;

@RestController
@RequestMapping("/order")
public class OrderController {
    @Resource
    private AccountService accountService;

    @Resource
    private StorageService storageService;

    @RequestMapping("list")
    public String list() {
        String s1 = accountService.list();
        String s2 = storageService.list();
        System.out.println(s1 + "," + s2);
        return "this is order list api";
    }
}

依然实现了服务调用,代码更加符合面向接口编程
在这里插入图片描述

路由网关

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
模块化后,订单服务、账户服务、仓储服务三个服务三个域名和三个端口,更多服务就更多个性化的东西。单前端来对接,就比较麻烦。
在这里插入图片描述
新建shopping-gateway8080子工程
在这里插入图片描述
pom.xml文件

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

动态路由规则uri:lb://服务名不生效,但是uri://https://www.baidu.com能够生效,说明缺少负载均衡依赖spring-cloud-loadbalancer
bootstrap.yml文件

server:
  port: 8080

spring:
  profiles:
    active: dev
  application:
    name: shopping-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: e122716d-7502-4505-9472-c73900e4aefd
        group: dev
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        refresh-enabled: true
        namespace: e122716d-7502-4505-9472-c73900e4aefd
        group: dev

GatewayMain8080主启动类

package vip.buddha;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

启动后,得在服务列表里找到这个网关服务,否则无法转发其它服务
在这里插入图片描述
新增shopping-gateway-dev.yaml配置文件,把路由网关配置写到这
在这里插入图片描述

spring:
  cloud:
    gateway:
      routes:
        - id: shopping-account
          uri: lb://shopping-account
          #uri: https://www.baidu.com
          predicates:
            - Path=/account/**
          filters:
            - StripPrefix=1

        - id: shopping-order
          uri: lb://shopping-order
          #uri: http://127.0.0.1:8001
          predicates:
            - Path=/order/**
          filters:
            - StripPrefix=1

        - id: shopping-storage
          uri: lb://shopping-storage
          #uri: https://www.baidu.com
          predicates:
            - Path=/storage/**
          filters:
            - StripPrefix=1

最终实现路由转发
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

服务熔断与限流

在这里插入图片描述
广州体育西路地铁下班高峰期,地铁把H口彻底给封上,G口留个口排队扫码进站。进去后也是层层关卡。这就是熔断和限流使用的表现。
网址:alibaba/Sentinel
在这里插入图片描述

java -jar sentinel-dashboard-1.8.3.jar --server.port=9500

在这里插入图片描述
在这里插入图片描述
账号和密码默认都是:sentinel,进来是下图的样子
在这里插入图片描述
以shopping-order服务为例
pom.xml文件加上以下内容:

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

shopping-order-dev.yaml加上以下内容:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: http://localhost:9500

访问url:http://localhost:8080/order/order/list,出现如下界面,说明sentinel整合成功!
在这里插入图片描述

定义全局降级方法和异常处理方法

在这里插入图片描述
CustomerBlockHandler文件代码:

package vip.buddha.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;

public class CustomerBlockHandler {
    public static String down_1(String type, String name, BlockException be) {
        System.out.println(be.getMessage());
        return "Sentinel 流控降级热点时调用的方法----111111---"+type+" "+name;
    }

    public static String down_2(String type, String name, BlockException be) {
        System.out.println(be.getMessage());
        return "Sentinel 流控降级热点时调用的方法----222222---" + type + " " + name;
    }
}

CustomerFallBack文件代码:

package vip.buddha.handler;

import org.springframework.web.bind.annotation.RequestParam;

public class CustomerFallBack {
    public static String fallback_1(@RequestParam(name = "type", required = false) String type,
                                    @RequestParam(name = "name", required = false) String name) {
        return "1111111111-------java代码运行时产生的异常调用,没有异常时该怎么运行,怎么运行 "+type+" "+name;
    }

    public static String fallback_2(@RequestParam(name = "type", required = false) String type,
                                    @RequestParam(name = "name", required = false) String name) {
        return "2222222222-------java代码运行时产生的异常调用,没有异常时该怎么运行,怎么运行 "+type+" "+name;
    }
}

OrderController文件代码:

package vip.buddha.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import vip.buddha.feign.AccountService;
import vip.buddha.feign.StorageService;
import vip.buddha.handler.CustomerBlockHandler;
import vip.buddha.handler.CustomerFallBack;

import javax.annotation.Resource;

@RestController
public class OrderController {
    @Resource
    private AccountService accountService;

    @Resource
    private StorageService storageService;

    @SentinelResource(value = "list",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "down_1",
            fallbackClass = CustomerFallBack.class,
            fallback = "fallback_1")
    @RequestMapping("/order/list")
    public String list(@RequestParam(name = "type", required = false) String type,
                       @RequestParam(name = "name", required = false) String name) {
        String s1 = accountService.list();
        String s2 = storageService.list();
        System.out.println(s1 + "," + s2);
        // 模拟报错
        //System.out.println(1 / 0);

        return "this is order list api" + type + " " + name;
    }
}

最后sentinel和Jmeter配合使用,达到接口限流和熔断效果

分布式事务

仓储服务、订单服务、账户服务,各自连不同的数据库,无法使用本地事务。seata是一款阿里开源的分布式事务解决方案。官方网址:https://seata.io/zh-cn,代码仓库网址:https://github.com/seata/seata/releases

搭建seata1.4.2服务端

在这里插入图片描述
解压后进入conf目录,备份file.conf和registry.conf配置
在这里插入图片描述

file.conf配置修改
## transaction log store, only used in seata-server
store {
  ## store mode: file、db、redis
  mode = "db"
  ## rsa decryption public key
  publicKey = ""
  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
    # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
    url = "jdbc:mysql://localhost:3306/seata?useUnicode=true&rewriteBatchedStatements=true&serverTimezone=GMT"
    user = "root"
    password = "root"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

  ## redis store property
  redis {
    ## redis mode: single、sentinel
    mode = "single"
    ## single mode property
    single {
      host = "127.0.0.1"
      port = "6379"
    }
    ## sentinel mode property
    sentinel {
      masterName = ""
      ## such as "10.28.235.65:26379,10.28.235.65:26380,10.28.235.65:26381"
      sentinelHosts = ""
    }
    password = ""
    database = "0"
    minConn = 1
    maxConn = 10
    maxTotal = 100
    queryLimit = 100
  }
}
registry.conf配置修改
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "dev"
    namespace = "e122716d-7502-4505-9472-c73900e4aefd"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = 0
    password = ""
    cluster = "default"
    timeout = 0
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
    aclToken = ""
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "e122716d-7502-4505-9472-c73900e4aefd"
    group = "dev"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
  consul {
    serverAddr = "127.0.0.1:8500"
    aclToken = ""
  }
  apollo {
    appId = "seata-server"
    ## apolloConfigService will cover apolloMeta
    apolloMeta = "http://192.168.1.204:8801"
    apolloConfigService = "http://192.168.1.204:8080"
    namespace = "application"
    apolloAccesskeySecret = ""
    cluster = "seata"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
    nodePath = "/seata/seata.properties"
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}
新增seataServer.properties配置文件

在这里插入图片描述

transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=true
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none
# server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
# store
#model改为db
store.mode=db
store.lock.mode=file
store.session.mode=file
# store.publicKey=""
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100
store.db.datasource=druid
store.db.dbType=mysql
#修改数据驱动,这里是mysql8,使用mysql5的话请修改
store.db.driverClassName=com.mysql.cj.jdbc.Driver
# 改为上面创建的seata服务数据库
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true&serverTimezone=GMT
# 改为自己的数据库用户名
store.db.user=root
# 改为自己的数据库密码
store.db.password=root
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
store.redis.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
# store.redis.sentinel.masterName=""
# store.redis.sentinel.sentinelHosts=""
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
# store.redis.password=""
store.redis.queryLimit=100
# log
log.exceptionRate=100
# metrics
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
# service
# 自己命名一个vgroupMapping   fsp_tx_group等下要用到  重中之重
service.vgroupMapping.shopping-tx-group=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
# client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=false
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
新增数据库配置
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
-- 分支表
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
-- 锁定表
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    PRIMARY KEY (`lock_key`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8mb4;
 
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

双击seata-server.bat,至此nacos服务端搭建完成
在这里插入图片描述
在这里插入图片描述

客户端使用seata1.4.2

准备工作

微服务整合seata客户端之前,完成微服务项目本身账户服务更改余额、仓储服务修改库存、订单服务调用账户服务、调用仓储服务、写入订单的功能。全局事务的引入,只是保证在异常情况出现时,能够保证数据一致。
在这里插入图片描述
三个微服务分别都引入下面三个依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
账户微服务
CREATE TABLE `account` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` int(10) unsigned NOT NULL COMMENT '用户ID',
  `money` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '账户余额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='账户表';

INSERT INTO `account` VALUES (1, 1, 1000);
INSERT INTO `account` VALUES (2, 2, 2000);

在这里插入图片描述

package vip.buddha.entity;

import lombok.Data;

@Data
public class Account {
    private Integer id;
    private Integer userId;
    private Integer money;
}
package vip.buddha.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vip.buddha.entity.Account;

@Mapper
public interface AccountMapper extends BaseMapper<Account> {
}
package vip.buddha.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import vip.buddha.entity.Account;
import vip.buddha.mapper.AccountMapper;

@Service
public class AccountService {
    @Autowired
    private AccountMapper accountMapper;

    public int updateByUserId(Integer userId, Account account) {
        QueryWrapper<Account> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        Account one = accountMapper.selectOne(wrapper);
        if (one.getMoney() < account.getMoney()) {
            return 0;
        }
        Account a = new Account();
        a.setId(one.getId());
        a.setMoney(one.getMoney() - account.getMoney());
        return accountMapper.updateById(a);
    }
}
package vip.buddha.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import vip.buddha.entity.Account;
import vip.buddha.service.AccountService;

@RestController
public class AccountController {
    @Autowired
    private AccountService accountService;

    @PutMapping("/account/{userId}")
    public Integer update(@PathVariable("userId") Integer userId, @RequestBody Account account) {
        Integer o = accountService.updateByUserId(userId, account);
        System.out.println(o);
        return o;
    }
}

shopping-account-dev.yaml配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/account?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: root
    
logging:
  level:
    root: info
    vip.buddha.mapper: debug
仓储服务
CREATE TABLE `storage` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `goods_id` int(10) unsigned NOT NULL COMMENT '商品ID',
  `num` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '商品库存',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品库存';

INSERT INTO `storage` VALUES (1, 1, 1000);
INSERT INTO `storage` VALUES (2, 2, 2000);

在这里插入图片描述

package vip.buddha.entity;

import lombok.Data;

@Data
public class Storage {
    private Integer id;
    private Integer goodsId;
    private Integer num;
}
package vip.buddha.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vip.buddha.entity.Storage;

@Mapper
public interface StorageMapper extends BaseMapper<Storage> {
}
package vip.buddha.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import vip.buddha.mapper.StorageMapper;
import vip.buddha.entity.Storage;

@Service
public class StorageService {
    @Autowired
    private StorageMapper storageMapper;

    public Integer updateByGoodsId(Integer goodsId, Storage storage) {
        QueryWrapper<Storage> wrapper = new QueryWrapper<>();
        wrapper.eq("goods_id", goodsId);
        Storage one = storageMapper.selectOne(wrapper);
        if (one.getNum() < storage.getNum()) {
            return 0;
        }
        Storage a = new Storage();
        a.setId(one.getId());
        a.setNum(one.getNum() - storage.getNum());
        return storageMapper.updateById(a);
    }
}
package vip.buddha.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import vip.buddha.entity.Storage;
import vip.buddha.service.StorageService;

@RestController
public class StorageController {
    @Autowired
    private StorageService storageService;

    @PutMapping("/storage/{goodsId}")
    public Integer update(@PathVariable("goodsId") Integer goodsId, @RequestBody Storage storage) {
        Integer i = storageService.updateByGoodsId(goodsId, storage);
        return i;
    }
}

shopping-storage-dev.yaml配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/storage?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: root
    
logging:
  level:
    root: info
    vip.buddha.mapper: debug
订单服务
CREATE TABLE `orders` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `goods_id` int(10) unsigned NOT NULL COMMENT '商品ID',
  `user_id` int(10) unsigned NOT NULL COMMENT '用户ID',
  `num` int(10) unsigned NOT NULL COMMENT '商品数量',
  `money` int(10) unsigned NOT NULL COMMENT '总价',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表';

在这里插入图片描述

package vip.buddha.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

import java.io.Serializable;

@Data
public class Orders implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private Integer goodsId;
    private Integer userId;
    private Integer num;
    private Integer money;
}
package vip.buddha.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import vip.buddha.entity.Orders;

@Mapper
public interface OrdersMapper extends BaseMapper<Orders> {
}
package vip.buddha.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import vip.buddha.entity.Account;

@Component
@FeignClient(value = "shopping-account")
public interface AccountService {
    @PutMapping("/account/{userId}")
    Integer update(@PathVariable("userId") Integer userId, @RequestBody Account account);
}
package vip.buddha.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import vip.buddha.entity.Storage;

@Component
@FeignClient(value = "shopping-storage")
public interface StorageService {
    @PutMapping("/storage/{goodsId}")
    Integer update(@PathVariable("goodsId") Integer goodsId, @RequestBody Storage storage);
}
package vip.buddha.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import vip.buddha.entity.Account;
import vip.buddha.entity.Orders;
import vip.buddha.entity.Storage;
import vip.buddha.feign.AccountService;
import vip.buddha.feign.StorageService;
import vip.buddha.mapper.OrdersMapper;

@Service
public class OrdersService {
    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private AccountService accountService;

    @Autowired
    private StorageService storageService;

    public int save(Orders orders) throws Exception {
        // 1. 扣余额
        Account a = new Account();
        a.setMoney(orders.getMoney());
        Integer i1 = accountService.update(orders.getUserId(), a);
        if (i1 == 0) {
            throw new Exception("扣余额失败");
        }
        // 2. 扣库存
        Storage s = new Storage();
        s.setNum(orders.getNum());
        Integer i2 = storageService.update(orders.getGoodsId(), s);
        if (i2 == 0) {
            throw new Exception("扣库存失败");
        }
        // 3. 添加订单记录
        int i = ordersMapper.insert(orders);
        return i;
    }
}
package vip.buddha.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import vip.buddha.entity.Orders;
import vip.buddha.service.OrdersService;

@RestController
@Slf4j
public class OrderController {
    @Autowired
    private OrdersService ordersService;

    @PostMapping("/order")
    public String save(@RequestBody Orders orders) throws Exception {
        int i = ordersService.save(orders);
        log.info(orders.toString());
        log.info("-----------------");
        log.info(" " + i);
        return "ok";
    }
} 

Seata客户端的配置

在账户服务、仓储服务、订单服务数据库中创建undo_log表

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

在这里插入图片描述
在账户服务、仓储服务、订单服务pom文件引入依赖,依赖版本要和seata服务端版本一致

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <exclusions>
        <!-- 要与seata服务端版本一直,所以把自带的替换掉 -->
        <exclusion>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.4.2</version>
</dependency>

在账户服务、仓储服务、订单服务的nacos配置文件中分别加入seata相关配置

seata: 
  enabled: true 
  enable-auto-data-source-proxy: true #是否开启数据源自动代理,默认为true
  tx-service-group: shopping-tx-group  #要与配置文件中的vgroupMapping一致
  registry:  #registry根据seata服务端的registry配置
    type: nacos #默认为file
    nacos:
      application: seata-server #配置自己的seata服务
      server-addr: localhost:8848 #根据自己的seata服务配置
      username: nacos #根据自己的seata服务配置
      password: nacos #根据自己的seata服务配置
      namespace: e122716d-7502-4505-9472-c73900e4aefd #根据自己的seata服务配置
      cluster: default # 配置自己的seata服务cluster, 默认为 default
      group: dev #根据自己的seata服务配置
  config:
    type: nacos #默认file,如果使用file不配置下面的nacos,直接配置seata.service
    nacos:
      server-addr: localhost:8848 #配置自己的nacos地址
      group: dev #配置自己的dev
      username: nacos #配置自己的username
      password: nacos #配置自己的password
      namespace: e122716d-7502-4505-9472-c73900e4aefd #配置自己的namespace
      dataId: seataServer.properties #配置自己的dataId,由于搭建服务端时把客户端的配置也写在了seataServer.properties,所以这里用了和服务端一样的配置文件,实际客户端和服务端的配置文件分离出来更好    

在账户服务、仓储服务、订单服务的主启动类上加上@EnableAutoDataSourceProxy注解
在需要事务的方法上加上@GlobalTransactional注解,用法如图
在这里插入图片描述
至此以SpringCloud Alibaba组件Nacos、Sentinel、Seata的微服务框架搭建完毕,其中也用到SpringCloud的组件,比如网关SpringCloud Gateway、远程调用SpringCloud OpenFeign等。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Cloud-Platform是国内首个基于Spring Cloud微服务化开发平台,具有统一授权、认证后台管理系统,其中包含具备用户管理、资源权限管理网关API 管理等多个模块,支持多业务系统并行开发,可以作为后端服务的开发脚手架。代码简洁,架构清晰,适合学习和直接项目中使用。 核心技术采用Spring Boot 2.1.2以及Spring Cloud (Greenwich.RELEASE) 相关核心组件,采用Nacos注册配置中心,集成流量卫兵Sentinel,前端采用vue-element-admin组件,Elastic Search自行集成。 软件特点: 中台化前端 集成d2admin中台化前端,优化前端架构和功能布局,支撑中台服务化的应用开发。 JWT鉴权 通过JWT的方式来进行用户认证和信息传递,保证服务之间用户无状态的传递。 监控 利用Spring Boot Admin 来监控各个独立Service的运行状态;利用Hystrix Dashboard来实时查看接口的运行状态和调用频率等。 负载均衡服务保留的rest进行代理和网关控制,除了平常经常使用的node.js、nginx外,Spring Cloud系列的zuul和ribbon,可以帮我们进行正常的网关管控和负载均衡。其中扩展和借鉴国外项目的扩展基于JWT的Zuul限流插件,方面进行限流。 服务注册与调用 基于Nacos来实现的服务注册与调用,在Spring Cloud中使用Feign, 我们可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。 熔断与流控 集成阿里Sentinel进行接口流量控制,通过熔断降级处理避免服务之间的调用“雪崩”。   Cloud Platform后台管理系统 更新日志: v3.1.0 1.升级spring cloud 2020.0.0 2.升级spring boot 2.4.1 3.升级spring cloud alibaba 2.2.4.RELEASE 4.Gateway切换Ribbon至LoadBalance
Spring Cloud Alibaba是一个基于Spring Cloud的开源框架,提供了丰富的微服务开发工具包,包括服务注册发现配置管理、消息总线、负载均衡熔断降级分布式事务、流量控制、安全控制、分布式追踪等功能。 Spring Cloud Alibaba与Nacos、Dubbo、Sentinel等组件协同工作,Nacos作为注册中心和配置中心,Dubbo作为RPC框架,Sentinel作为流量控制和熔断降级组件,共同构建起完整的微服务生态体系。 使用Spring Cloud Alibaba进行服务注册发现,可以通过注解@EnableDiscoveryClient开启服务注册发现功能,并通过@FeignClient或@LoadBalanced注解实现服务调用和负载均衡。 使用Spring Cloud Alibaba进行服务治理,可以通过注解@EnableCircuitBreaker开启熔断降级功能,并通过@SentinelResource注解配置熔断降级规则。 使用Spring Cloud Alibaba进行熔断降级,可以通过Sentinel Dashboard进行实时监控和管理,同时通过注解@SentinelRestTemplate实现对RestTemplate的熔断降级。 使用Spring Cloud Alibaba进行服务配置管理,可以通过注解@EnableConfigNacosConfig和@Value注解实现动态配置管理。 使用Spring Cloud Alibaba进行分布式事务管理,可以通过注解@EnableDistributedTransaction开启分布式事务管理功能,并通过@GlobalTransactional注解实现分布式事务的统一管理和控制。 使用Spring Cloud Alibaba进行链路追踪,可以通过注解@EnableZipkinServer和@EnableZipkinClient开启链路追踪功能,并通过Sleuth和Zipkin实现对微服务调用链的追踪和分析。 使用Spring Cloud Alibaba进行服务限流,可以通过Sentinel进行实时流控和熔断降级,同时通过注解@SentinelResource实现对服务的限流控制。 Spring Cloud Alibaba支持微服务服务网关管理,可以通过注解@EnableZuulProxy或@EnableGateway开启服务网关功能,并通过Zuul或Gateway实现微服务的API网关管理

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员buddha

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值