微服务SpringCloud

2023-11-05

什么是SpringCloud

SpringCloud是由Spring提供的一套能够快速搭建微服务架构程序的框架集

SpringCloud本身不是一个框架,而是一系列框架的统称

SpringClound就是为了搭建微服务架构才出现的

有人将SpringCloud称之为"Spring全家桶",广义上代指所有Spring的产品

SpringCloud的内容

内容的提供者角度

Spring自己编写的框架和软件

Netflix(奈非):早期提供了很多微服务组件

alibaba(阿里巴巴):新版本SpringCloud推荐使用(使用频率迅速提升)

从功能上分类

微服务的注册中心

微服务间的调用

微服务的分布式事务

微服务的限流

微服务的网关

.............

Nacos注册中心

什么是Nacos

Nacos是Spring Cloud Alibaba提供的一个软件

这个软件具有微服务注册中心功能

也就是当前微服务架构中的所有微服务项目都需要到Nacos注册才能成为这个微服务项目的一部分

Nacos是一个能够接收所有微服务项目信息的组件

只有将信息"注册"到Nacos,这个项目才会成为微服务架构中的一个组成部分

安装和启动Nacos

前提

需要当前计算机安装并配置java环境变量

因为Nacos是java开发的,所以要运行必须配置java环境变量

Nacos 下载路径:

https://github.com/alibaba/nacos/releases/download/1.4.3/nacos-server-1.4.3.zip

Nacos心跳机制

面试题

Nacos系统内置周期性检查和报告工作,称之为"心跳"

客户端或服务器会周期的检查状态,运行固定代码,保证能够检测模块

Nocos实例的心跳又分为类两种

临时实例心跳

永久实例心跳

在后面配置中,如果采用默认配置,当前实例就是永久实例

spring:
  application:
    name: xxxx
  cloud:
    nacos:
      discovery:
        ephemeral: false # 默认false实例为永久实例。true:临时; false:永久
      	server-addr: localhost:8848

临时实例基于心跳方式做健康检测

永久实例是Nacos主动探测健康状态

临时实例

客户端(各个模块)每隔五秒自动向Nacos发送心跳包

包中包含微服务名称,ip地址 port(端口号),集群名称信息

Nacos接收到信息后,判断当前Nacos中是否包含这个包中的信息

  ****如果不包,证明这是一个新的实例,进行注册操作

 ****如果存在,记录本次心跳时间,设置为健康状态

整体流程有个别名:"心跳续约"

永久实例

永久实例是Nacos周期性向客户端进行检测

Nacos每隔15秒向客户端发送一个检测请求,如果第一个15 秒客户端没有给出响应,就会被标记为"肺健康状态"

如果两个连续的15秒(一共30秒)都没有响应,就会从注册列表中剔除这个服务

整体流程有个别名"心跳检测"

安装启动Nacos

将压缩包解压(注意不要有中文路径或空格)

打开解压得到的文件夹后打卡bin目录会有如下内容

startup.cmd是windows系统启动Nacos的命令

shutdown.cmd是windows系统停止Nacos的命令

.sh结尾的文件是linux和mac系统的启动和停止文件

启动Nacos不能直接双击startup.cmd

而需要打开dos窗口来执行

Win+R输入cmd

 如果不指定会默认以集群模式运行,无法完成功能

如果运行成功会显示8848端口

打开浏览器输入地址

http://localhost:8848/nacos

 如果首次访问没有响应,可以尝试从新解压和运行,再访问

登录系统

用户名和密码都是nacos

进入后会看到列表后台

注意不要关闭doc窗口,一旦关闭,nacos就停止了

将项目注册到Nacos的配置

要注册到Nacos的项目添加如下配置即可

添加pom.xml文件依赖

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

application-dev.yml文件添加配置

spring:
  application:
    name: nacos-business # 定义当前服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # 指定正在运行的Nacos服务器的位置

上面配置中nacos-business是当前服务名称,每个不同功能模块名称要不同

nacos ip地址和端口号根据实际情况编写

我们启动business,在nacos服务列表中观察

出现信息表示一切正常

可以复制项目然后修改端口号,启动同名服务的项目,这样服务列表中就出现多个实例

实际开发中,一般情况都会有多个实例去分但同一个服务

使用Idea启动Nacos

每次开机都需要启动Nacos

 点击Ok确定之后

项目的启动中就会出现Nacos的启动项了

DUBBO概述

了解一下RPC的概念

RPC是Remote Procedure Call 翻译为: 远程过程调用

它是为了实现两个不再一起的服务器\计算机,实现相互调用方法的解决方案

RPC主要包含了2个部分的内容

序列化协议

通信协议

理解PRC的概念图

 如果远程调用如下图

通信协议:

当老婆在外面时,需要借助通讯工具通知老公来完成什么操作

在这个流程中通信协议就指老婆使用什么方式通知老公要洗碗

可以是手机,也可以写信,可以飞鸽传书

序列化协议指传输信息的内容是什么格式,双方都要能够理解这个格式

 例如老婆说中文,老公要理解中文,其他语言也一样

发送信息是序列化的过程,接收信息是反序列化的过程

这样他们才能明确调用的目的

这样的流程就是我们生活中的RPC使用的场景

什么是Dubbo

Dubbo是一套RPC框架,既然是框架,我们可以在框架结构高度,定义Dubbo中使用通信协议,使用的序列化框架技术,而数据格式由Dubbo定义,我们负责配置之后直接通过客户端调用服务端代码

Dubbo中默认的通信协议是Dubbo自己写的协议

序列化协议使用的就是我们之前用过的json

但是我们也要知道,通信协议和序列化协议是可以通过配置文件修改的

使用的生活中老婆和老公的例子 在程序是什么样的模型呢

发起调用的一方从当前项目的业务层,调用被调用一方的业务层方法

也可能是发起调用的一方从控制层,调用被调用一方的业务层方法

总的来说,被调用的方法一定是业务逻辑层方法

Dubbo框架的优点之一就是没有破坏controller>service>mapper的运行流程

Dubbo的发展历程

 Dubbo特性

因为Dubbo内置了序列化协议和通信协议,所有会有下面的特征

采用NIO单一长链接

优秀的高并发处理性能

编写简单 提升开发效率

Dubbo的注册与服务的发 

使用Dubbo实现远程调用必须有Nacos的支持

服务发现,即消费端自动发现服务地址列表的能力,是微服务框架需要具备的关键能力,借助于自动化的服务发现,微服务之间可以在无需感知对端部署位与IP地址的情况下实现通信

服务的消费者就是服务的调用者(老婆)

服务的生产者就是服务的提供者(老公)

Dubbo调用远程服务,无需要指定IP地址端口号,只需要知道它的服务名称即可

一个服务名称可能有多个运行的实例,任何一个空闲都可以提供服务

 Dubbo注册流发现流程

1. 首先服务的提供者启动服务到Nacos注册中心进行注册,包括各种ip端口信息,Dubbo会同时注册该项目提供远程调用的方法

2.服务的消费者(使用者)注册到注册中心 即 订阅发现

3.当有新的远程调用方法注册到注册中心时,注册中心会通知服务的消费者有哪些新的方法,如何调用的信息

4.RPC调用,在上面条件满足的情况下,服务的调用者无需知道ip和端口号,只需要服务名称机也可以调用到服务提供者的方法

Dubbo的使用

了解调用流程

 添加Dubbo的依赖和支持

STOCK模块

stock模块中要创建一个新的项目csmall-stock-service

删除test\删除resources\删除SpringBoot启动类

这个项目就是一个保存业务逻辑层接口的项目

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>cn.tedu</groupId>
        <artifactId>csmall-stock</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-stock-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>csmall-stock-service</name>
    <description>Demo project for Spring Boot</description>
    <dependencies>
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>csmall-commons</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

复制IStockService到当前项目

public interface IStockService {
    void reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO);
}

 在stock模块中在创建一个字项目csmall-stock-webapi

删除test文件夹

然后复制原stock的依赖到webapi然添加dubbo的依赖

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>cn.tedu</groupId>
        <artifactId>csmall-stock</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-stock-webapi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>csmall-stock-webapi</name>
    <description>Demo project for Spring Boot</description>
    <dependencies>
        <!--web实例-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mybatis整合springboot-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--alibaba 数据源德鲁伊-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--all-common依赖-->
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>csmall-commons</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!--在线api文档-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
        </dependency>
        <!--  Nacos注册依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Dubbo依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <!-- 添加csmall-stock-service的依赖 -->
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>csmall-stock-service</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

 csmall-stock二级父项目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>cn.tedu</groupId>
        <artifactId>csmall</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-stock</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>csmall-stock</name>
    <description>Demo project for Spring Boot</description>

    <packaging>pom</packaging>
    <modules>
        <module>csmall-stock-service</module>
        <module>csmall-stock-webapi</module>
    </modules>
</project>

将原有csmall-stock的application.yml和application-dev.yml复制到csmall-stock-webapi项目的resources文件夹下

在application-dev.yml添加dubbo的依赖

spring:
  application:
    name: nacos-stock # 定义当前服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # 指定正在运行的Nacos服务器的位置
  datasource:
    url: jdbc:mysql://localhost:3306/csmall_db?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
    username: root
    password: root
dubbo:
  application:
    name: nacos-stock  # 一般情况下会和spring.application.name设置一样的值,默认也是这个值,可以省略
  protocol:
    port: -1  # 设置dubbo服务调用的端口 设置-1表示自动生成,生成规则是从20880开始递增
    name: dubbo  # 端口名称固定dubbo即可
  registry:
    address: nacos://localhost:8848  # 表示当前Dubbo的注册中心类型是Nacos,地址是后面的内容
  consumer:
    check: false # 设置false表示服务启动时,不检查标定的可调用的远程服务是否存在,避免报错

将csmall-stock中所有java类(除了业务逻辑层接口)都复制到webapi项目中完成一些必要要的包配置的变化

Knife4jConfiguration:

/**
 * 【重要】指定Controller包路径
 */
private String basePackage = "cn.tedu.csmall.stock.webapi.controller";

MyBatisConfiguration

@Configuration
@MapperScan("cn.tedu.csmall.stock.webapi.mapper")
public class MyBatisConfiguration {
}

StockServiceImpl

// ↓↓↓↓↓↓↓↓
@DubboService
@Service
@Slf4j
public class StockServiceImpl implements IStockService {
    @Autowired
    private StockMapper stockMapper;
    @Override
    public void reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO) {
        log.info("控制层调用减少商品库存--开始");
        stockMapper.updateStockCountByCommodityCoud(stockReduceCountDTO.getCommodityCode(),stockReduceCountDTO.getReduceCount());
        log.info("商品减库存入库--结束");
    }
}

CsmllStockWebapiApplication启动类

@SpringBootApplication
// ↓↓↓↓↓↓↓↓
@EnableDubbo
public class CsmallStockWebapiApplication {

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

删除stock模块的src

cart模块

操作步骤和stock模块一致

修改order模块

只是csmall-order-webapi项目pom文件需要添加stock和cart的业务逻辑依赖

<!--   Dubbo依赖     -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-order-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 因为order模块要调用stock和cart的功能  -->
<!-- 所以我们要添加stock和cart的业务逻辑层接口项目(service)的依赖  -->
<dependency>
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-cart-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-stock-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

还有就是业务逻辑层实现有修改

之前order模块只是单纯的添加订单信息到数据库 现在我们要在添加订单到数据库之前先删除库存和购物车的信息

@DubboService
@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {
    @Autowired
    private OrderMapper orderMapper;
    // 当前业务逻辑层要调用库存模块的减少库存方法
    @DubboReference
    private IStockService dubboStockService;
    // 当前业务逻辑层要调用购物车模块的删除购物车中商品的方法
    @DubboReference
    private ICartService dubboCartService;

    @Override
    public void orderAdd(OrderAddDTO orderAddDTO) {
        // 这里新增订单要先减少库存(要调用stock项目的方法)
        // dubbo远程调用,减少库存
        // 实例化减少库存需要的对象
        StockReduceCountDTO stockReduceCountDTO=new StockReduceCountDTO();
        // 赋值减少库存数
        stockReduceCountDTO.setReduceCount(orderAddDTO.getCount());
        // 赋值减少商品编号
        stockReduceCountDTO.setCommodityCode(orderAddDTO.getCommodityCode());
        // 执行减少库存
        dubboStockService.reduceCommodityCount(stockReduceCountDTO);
        // 再删除购物车中的商品(要调用cart项目的方法)
        dubboCartService.deleteUserCart(orderAddDTO.getUserId(),
                                        orderAddDTO.getCommodityCode());
        // 实例化订单对象
        Order order=new Order();
        // 同名属性复制
        BeanUtils.copyProperties(orderAddDTO,order);
        orderMapper.insertOrder(order);
        log.info("新增订单完成!{}",order);
    }
}

别忘了添加@EnableDubbo

@SpringBootApplication
// ↓↓↓↓↓↓↓↓↓↓↓↓
@EnableDubbo
public class CsmallOrderWebapiApplication {

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

}

business调用

business模块是整个业务的起点

它是单纯的服务消费者,所以不需要在创建两个子项目了

只需添加dubbo依赖调用order的业务逻辑层方法即可

<!--  Dubbo依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
    <groupId>cn.tedu</groupId>
    <artifactId>csmall-order-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

application-dev.yml

spring:
  application:
    name: nacos-business # 定义当前服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # 指定正在运行的Nacos服务器的位置
dubbo:
  protocol:
    port: -1  # 设置dubbo服务调用的端口 设置-1表示自动生成,生成规则是从20880开始递增
    name: dubbo  # 端口名称固定dubbo即可
  registry:
    address: nacos://localhost:8848  # 表示当前Dubbo的注册中心类型是Nacos,地址是后面的内容
  consumer:
    check: false # 设置false表示服务启动时,不检查标定的可调用的远程服务是否存在,避免报错

在busuiness模块的业务逻辑层调用order的添加订单的方法

BusinessServiceImpl修改代码如下:

@Service
@Slf4j
public class BusinessServiceImpl implements IBusinessService {

    @DubboReference
    private IOrderService dubboOrderService;

    @Override
    public void buy() {

        OrderAddDTO orderAddDTO=new OrderAddDTO();
        orderAddDTO.setCommodityCode("PC100");
        orderAddDTO.setUserId("UU100");
        orderAddDTO.setCount(5);
        orderAddDTO.setMoney(500);
        log.info("要新增的订单信息为:{}",orderAddDTO);
        // 远程调用新增订单的方法
        dubboOrderService.orderAdd(orderAddDTO);
    }
}

别忘了添加@EnableDubbo

@SpringBootApplication
//  ↓↓↓↓↓↓↓↓↓↓
@EnableDubbo
public class CsmallBusinessApplication {

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

}

启动所有4个项目

进入20000端口测试business模块发起业务调用

如果能够顺利新增订单.表示一切ok

什么是Seata

Seata官方文档

Seata

是阿里巴巴提供的SpringCloud组件

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

为什么需要Seata 

事务的4个特性:ACID特性

原子性

一致性

隔离性

永久性

其中最重要的原子性能保证整体业务运行中所有操作要么都成功,要么都失败

分布式事务和之前学习的Spring声明式事务不同

它不是一个项目的数据库操作,所以不能简单的通过一个数据库事务就完成

每个项目都有自己的数据库事务,那么要想在多个事务的提交过程中在添加支持他们事务就需要Seata

Seata将为用户提供了 AT TCC  SAGA 和 XA事务模式,为用户打造一站式分布解决方案

Seata的运行原理

这里以AT模式为例讲解原理

 上面的结构和我们的课程中类似,可以方便理解

当account操作失败时,要让已经操作完成的order撤销操作

也要让stoage撤销操作

不使用分布式事务非常难以处理

Seata的At模式格式如下,来解决这个问题

 Seata构成

事务协调器TC

事务管理器TM

资源管理器RM

AT模式运行过程

1 事务的发起方(TM)会向事务协调器(TC)申请一个全局事务id,并保存

2 Seata会管理事务中所有相关的参与方的数据源,将数据操作之前和之后的镜像都保存在undo_lug表中,这个表是seata框架规定的,方便提交(commit)或回滚(roll back)

3事务的发起方(TM)会连同全局id一起通过远程调用运行资源管理器(RM)中的方法

4 资源管理器(RM)接受到全局id,并运行指定的方法,将运行的状态同步到事务协调器(TC)

5 如果运行整体没有发生异常,发起方(TM)会通过事务协调器所有分支,将本次事务所有对数据库的影响真正生效

如果有任何一个参与者发生异常,那么都会通知事务协调器,在由事务协调器通知有分支,根据

undo-log表中保存的信息,撤销(回滚)即将正式影响数据库的数据

除AT模式外的其他的模式简介

Seata将为用户提供了 AT TCC SAGA和 XA事务模式

AT模式只能用于数据操作事务

如果事务中有的参与者操作的不是关系型数据库(例如操作Redis)

那么AT模式就不能生效了

TCC模式

这个模式可以实现对数据库之外的信息存储媒介进行回滚操作

只不过这个回滚需要我们自己编写代码

需要为每个业务编写Prepare\Commit\Rollback方法

Prepare编写常规准备 如果整个业务运行无异常运行Commit,如果有异常会自动运行Rollback

缺点是每个业务都需要编写3个对应的方法,代码有冗余 而且业务入侵量大

SAGA模式

一般用于修改老版本代码

不用编写象TCC模式那多的方法

但是需要手动编写每个参与者的方向回滚业务逻辑层代码类

开发量大

XA 模式

XA是适用于支持XA协议的数据库,使用的比较少

下载Seata

Releases · seata/seata · GitHub

https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip

配置Seata支持

cart\stock\order模块的pom文件添加下面支持

<!--   Seata和SpringBoot整合依赖     -->
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
</dependency>
<!--  Seata 完成分布式事务的两个相关依赖(Seata会自动使用其中的资源)  -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>

上述模块还要修改yml文件

application-dev.yaml

seata:
  tx-service-group: csmall_group # 分组
  service:
    vgroup-mapping:
      csmall_group: default # 默认at模式
    grouplist: 
      default: localhost:8091

配置中,同一个事务的多个参与者必须在同一个名称的分组下

同时制定相同的seata-server的ip和端口

business模块配置更简单

pom文件只加一个依赖

<!--   Seata和SpringBoot整合依赖     -->
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
</dependency>

application-dev.yaml和之前的一样

seata:
  tx-service-group: csmall_group # 分组
  service:
    vgroup-mapping:
      csmall_group: default # 默认at模式
    grouplist:
      default: localhost:8091

当前项目模型中,business是事务的发起者

发起者组织事务开始

必须由特定的注解标记业务逻辑层方法(@GlobalTrancsational)

在这个方法运行时会激活Seata的分布式事务管理流程

@Service
@Slf4j
public class BusinessServiceImpl implements IBusinessService {

    @DubboReference
    private IOrderService dubboOrderService;

    // 下面的注解是激活seata分布式事务管理 并开始运行的标记注解
    @GlobalTransactional
    @Override
    public void buy() {

        OrderAddDTO orderAddDTO=new OrderAddDTO();
        orderAddDTO.setCommodityCode("PC100");
        orderAddDTO.setUserId("UU100");
        orderAddDTO.setCount(5);
        orderAddDTO.setMoney(500);
        log.info("要新增的订单信息为:{}",orderAddDTO);
        // 远程调用新增订单的方法
        dubboOrderService.orderAdd(orderAddDTO);
        // 下面来编写代码随机抛出异常
        // 注意这个位置发生异常的话,实际上前面已经运行完毕了orderAdd方法
        // 我们需要观察随机发生异常时,各个表中的数据 是否能够回滚到方法运行之前的状态
        if(Math.random()<0.5){
            // 手动抛出自定义异常
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"发送随机异常");
        }
    }
}

启动Seata

 

 

启动所有4个服务

运行knife4j测试

测试business模块,如果能够运行出现成功或出现异常的提示信息

并在数据库中呈现正常运行或回滚的效果,表示一切正常

在windows系统中运行seata可能出现不稳定的情况,重启seata即可解决

Sentinel

什么是Sentinl 

Sentil也是阿里巴巴提供的SpringCloud组件

Sentinel 英文意思"哨兵\门卫"

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

Sentinel特征

丰富的应用场景

双11,秒杀,12306抢火车票

完备的实时状态监控

可以支持显示当前项目各个服务的运行和压力状态,分析出每台服务器处理的秒级别的数据

广泛的开源生态:

很多技术可以和Sentinel进行整合,SpringCloud,Dubbo 而且依赖少配置简单

完善的SPI扩展

Sentinel支持程序设置各种自定义的规则

下载地址

Releases · alibaba/Sentinel · GitHub

 基本配置和限流效果

我们先在库存模块进行限流测试

以stock-webapi库存模块为例

添加依赖pom文件如下

<!--   Sentinel整合SpringCloud     -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

application-dev.yml配置Sentinel支持

spring:
  application:
    name: nacos-stock # 定义当前服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # 指定正在运行的Nacos服务器的位置
    sentinel:
      transport:
        dashboard: localhost:8080  # Sentinel仪表台的ip:端口
        port: 8721  # 是localhost的8721 这个端口真正参与当前项目的限流措施

其中port: 8721这个端口号每个项目都不能一样

配置准备工作完毕

下面要使用注解标记限流的控制层方法

在stock-wenapi中的StockController类中控制器方法前添加注解

代码如下:

@PostMapping("/reduce/count")
@ApiOperation("商品库存减少")
// ↓↓↓↓↓↓↓↓↓↓↓↓
@SentinelResource
public JsonResult reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO){
    stockService.reduceCommodityCount(stockReduceCountDTO);
    return JsonResult.ok("商品减少库存完成!");
}

 运行控制器方法之后

Sentinel的仪表台就能设置这个控制方法的限流规则了

QPS是每秒请求数

并发线程数是同时方法这个方法的线程数量

超出的部分都会被Sentinel限流 快速失败

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

微服务SpringCloud 的相关文章

随机推荐

  • C++primer 阅读随记

    目 录 一 C 基础 1 变量和基本类型 2 字符串 向量和数组 3 表达式 4 语句 5 函数 6 类 二 C 标准库 1 IO库 2 顺序容器 3 泛型算法 4 关联容器 5 动态内存 三 类设计者的工具 1 拷贝控制 2 重载运算与类
  • 实施Microsoft Dynamics 365 CE-5. 配置Dynamics 365 CE组织,包括配置不同的Dynamics 365 CE设置。

    本章将帮助您了解Dynamics 365 CE中为个人和管理员提供的Dynamics 365配置选项 您将了解哪些选项可以为单个用户配置 哪些是管理员用户可以完成的配置 您将了解业务管理和服务管理设置下提供的不同配置选项 您还将了解Dyna
  • RobotFramework之高级API

    一 窗口跳转 跳转页面的时候需要获取句柄 Get Window Handles 获取窗口的句柄 Select Window By Handle 切换到新窗口 但是在seleniumLibrary中只有Select window 所以我们进入
  • Top K问题的两种解决思路

    Top K问题在数据分析中非常普遍的一个问题 在面试中也经常被问到 比如 从20亿个数字的文本中 找出最大的前100个 解决Top K问题有两种思路 最直观 小顶堆 大顶堆 gt 最小100个数 较高效 Quick Select算法 Lee
  • 自适应表格中input框输入文字布局被打乱

    我今天在写一个新增用户表单的时候 发现我只要输入文字 input框的高度就会改变 导致布局被打乱 这是正常排列好的样式 这是我输入中文后的样子 后来我发现输入中文后 input的高度被撑开了 我一开始没有给盒子设置固定的高度以及行高 设置完
  • C 语言基础-什么是常量、变量?

    C 语言基础 常量和变量 常量 只读 常量是只读的固定值 在程序运行期间不会改变 不能被程序修改的量 可以是任意类型 定义常量的方式有两种 使用 define 宏定义 使用 const 关键字 常量大体分为 直接常量 字面常量 符号常量 d
  • python练习61:打印出杨辉三角形,包含二维列表的应用

    打印出杨辉三角形 要求打印出10行如下图 yanghui for i in range 10 yanghui append 构造二维列表 for j in range i 1 if j 0 or j i yanghui i append 1
  • CCF-CSP真题-2022-06-1归一化处理讲解

    题目传送门 这是CCF CSP2022 06的第一题 相比较还是比较简单 较难理解的是方差 每个样本值与全体样本值的平均数之差的平方值的平均数方差 数学计算公式是这样的 然而 用代码来写要简洁得多 这里采用暴力的复杂度算法 for int
  • MySQL utf8mb4 字符集,用于存储emoji表情

    最近在做微信相关的项目 其中MySQL 要存储emoji表情 因此发现我们常用的utf8 字符集根本无法存储表情 网上有不少替代方案 本人还是采用了修改MySQL字符集的方案简单快捷 首先将我们数据库默认字符集由utf8 更改为utf8mb
  • Pandas分组与排序

    Grouping and Sorting 分组 agg 排序 经常需要将数据根据某个字段划分为不同的组 group 进行分析 然后对组里的数据进行特定的操作 pandas的 groupby 操作便是实现这一功能 groupby的过程就是将原
  • jquery的两种常用自动加载方法

    一 jquery JavaScript的三种常用自动加载方法 1 function jQuery 2 function 3 window nl ad function 加载的先后顺序 第一步 代码块1加载 是在css html 信息加载完毕
  • Scala环境配置完成,在命令行还是不能运行

    刚开始我以为是版本兼容的问题 所以下载了很多个版本 发现没用 我找了很久都不知道是什么原因 网上也没找到跟我一样的问题 偶然我发现是系统环境变量PATHEXT中缺少东西 在PATHEXT中添加 bat 然后就可以了
  • AIX系统安装

    1 选择安装介质 CD ROM 现有备份的安装系统 网络安装 Token Ring Ethernet FDDI U盘 服务器通电启动系统 在控制台显示器出现keyboard字符时 按对应的按钮 1 进入系统管理服务模式 SMS 2 指定控制
  • C语言中结构体初始化并清零的方法有几种?

    结构体初始化清零方法 在C语言中 结构体初始化并清零的方法有以下几种 手动赋值为0 结构体定义后在函数内手动将每个成员都赋值为0 例如 struct MyStruct int a char b float c struct MyStruct
  • vue页面基本组成

    作为编写过html的人 vue页面的基本组成是什么呢 如何快速入手vue呢 我来讲下自己的思路 简介 vue是一个前端框架 运行它需要下载node js 后台支撑 下载vs code 代码编辑器 来编辑代码 可配合eliment ui 上百
  • nodejs处理图片文件上传

    如果使用express框架的话 其内置模块就可以直接处理文件上传了 而不需要饱含额外的模块 express版本 3 4 4 1 使用bodyParser过滤器 并且指定上传的目录为public upload 注意这里的目录为相对于expre
  • PyQt5学习笔记--GridLayout、FormLayout和StackedLayout布局

    目录 1 GridLayout布局 2 FormLayout布局 3 StackedLayout布局 1 GridLayout布局 import sys from PyQt5 QtWidgets import class MyWindow
  • select、poll、epoll

    因为实际需要所致 我们不得不考虑在现有的开源 商用的应用服务器之外开发一个 有性能要求 有并发要求的服务端应用 从技术要求的角度来分析一下 用Java实现这件事情我们可能关注的知识层面 在整体上 可能需要我们从下面几个层面出发来考虑 1 在
  • windows多个不同java共存

    windows多个不同java共存 如图我电脑存在java1 8和15 使用时 我会存在工具支持的java版本不一样 有的工具要8才能使用有的工具需要11或者15以上java才能正常使用 于是为了方便快捷便写了这个多java版本共存 jav
  • 微服务SpringCloud

    什么是SpringCloud SpringCloud是由Spring提供的一套能够快速搭建微服务架构程序的框架集 SpringCloud本身不是一个框架 而是一系列框架的统称 SpringClound就是为了搭建微服务架构才出现的 有人将S