• JSD-2204-Dubbo实现微服务调用-Seata-Day03


    1.Dubbo实现微服务调用

    1.1确定调用关系

    • order模块调用stock模块的减少库存的功能

    • order模块调用cart模块的删除购物车的功能

    • business模块调用order新增订单的功能

    要想实现Dubbo调用

    必须按照Dubbo规定的配置和行业标准的结构来实现

    Dubbo调用的好处是直接将要消费的目标(例如order模块中消费stock的方法)编写在当前消费者的业务逻辑层中,无需编写新的代码结构,开发流程不会因为Dubbo而变化

    1.2修改stock模块

    1.2.1创建csmall-stock-service项目

    因为当前stock模块减少库存数业务是典型的生成者方法,需要被别的模块调用

    那么其它模块就必须添加当前库存数减少的业务接口支持

    为了减少添加这个给当前项目带来的负担

    业界通用做法,是将生产者项目拆分为两个,

    其中一个项目只有业务逻辑层接口

    另一个项目包含正常的配置和所有业务代码

    当消费者需要时只需要添加包含业务逻辑层接口的项目的依赖即可

    创建csmall-stock-service项目

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

    csmall-stock升格为父项目,所以也要修改它的pom文件

    1. <description>Demo project for Spring Bootdescription>
    2. <packaging>pompackaging>
    3. <modules>
    4. <module>csmall-stock-servicemodule>
    5. modules>

    csmall-stock-service项目的pom文件添加最低要求的依赖

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <parent>
    6. <groupId>cn.tedugroupId>
    7. <artifactId>csmall-stockartifactId>
    8. <version>0.0.1-SNAPSHOTversion>
    9. <relativePath/>
    10. parent>
    11. <groupId>cn.tedugroupId>
    12. <artifactId>csmall-stock-serviceartifactId>
    13. <version>0.0.1-SNAPSHOTversion>
    14. <name>csmall-stock-servicename>
    15. <description>Demo project for Spring Bootdescription>
    16. <dependencies>
    17. <dependency>
    18. <groupId>cn.tedugroupId>
    19. <artifactId>csmall-commonsartifactId>
    20. <version>0.0.1-SNAPSHOTversion>
    21. dependency>
    22. dependencies>
    23. project>

    然后将原有的业务逻辑层接口IStockService复制到这个项目中即可

    1. public interface IStockService {
    2. // 根据商品编号减少库存的方法
    3. void reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO);
    4. }

    1.2.2创建csmall-stock-webapi项目

    webapi项目包含stock项目原有的所有配置和业务代码

    创建好项目之后删除test文件夹、删除application.properties文件

    然后父子相认

    最终csmall-stock项目的pom文件为

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <parent>
    6. <groupId>cn.tedugroupId>
    7. <artifactId>csmallartifactId>
    8. <version>0.0.1-SNAPSHOTversion>
    9. <relativePath/>
    10. parent>
    11. <groupId>cn.tedugroupId>
    12. <artifactId>csmall-stockartifactId>
    13. <version>0.0.1-SNAPSHOTversion>
    14. <name>csmall-stockname>
    15. <description>Demo project for Spring Bootdescription>
    16. <packaging>pompackaging>
    17. <modules>
    18. <module>csmall-stock-servicemodule>
    19. <module>csmall-stock-webapimodule>
    20. modules>
    21. project>

    csmall-stock-webapi项目的pom文件为

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <parent>
    6. <groupId>cn.tedugroupId>
    7. <artifactId>csmall-stockartifactId>
    8. <version>0.0.1-SNAPSHOTversion>
    9. <relativePath/>
    10. parent>
    11. <groupId>cn.tedugroupId>
    12. <artifactId>csmall-stock-webapiartifactId>
    13. <version>0.0.1-SNAPSHOTversion>
    14. <name>csmall-stock-webapiname>
    15. <description>Demo project for Spring Bootdescription>
    16. <dependencies>
    17. <dependency>
    18. <groupId>org.springframework.bootgroupId>
    19. <artifactId>spring-boot-starter-webartifactId>
    20. dependency>
    21. <dependency>
    22. <groupId>org.mybatis.spring.bootgroupId>
    23. <artifactId>mybatis-spring-boot-starterartifactId>
    24. dependency>
    25. <dependency>
    26. <groupId>com.alibabagroupId>
    27. <artifactId>druidartifactId>
    28. dependency>
    29. <dependency>
    30. <groupId>mysqlgroupId>
    31. <artifactId>mysql-connector-javaartifactId>
    32. dependency>
    33. <dependency>
    34. <groupId>cn.tedugroupId>
    35. <artifactId>csmall-commonsartifactId>
    36. <version>0.0.1-SNAPSHOTversion>
    37. dependency>
    38. <dependency>
    39. <groupId>com.github.xiaoymingroupId>
    40. <artifactId>knife4j-spring-boot-starterartifactId>
    41. dependency>
    42. <dependency>
    43. <groupId>com.alibaba.cloudgroupId>
    44. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    45. dependency>
    46. <dependency>
    47. <groupId>com.alibaba.cloudgroupId>
    48. <artifactId>spring-cloud-starter-dubboartifactId>
    49. dependency>
    50. <dependency>
    51. <groupId>cn.tedugroupId>
    52. <artifactId>csmall-stock-serviceartifactId>
    53. <version>0.0.1-SNAPSHOTversion>
    54. dependency>
    55. dependencies>
    56. project>

    1.2.3上面的pom文件不只是将原有的stock的pom文件依赖复制,而且添加了Dubbo和业务逻辑层接口的依赖

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

    yml文件其它的不动,但是在dev.yml文件中要添加dubbo的配置信息

    1. spring:
    2. datasource:
    3. url: jdbc:mysql://localhost:3306/csmall_db?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
    4. username: root
    5. password: root
    6. application:
    7. # 为当前项目起名,这个名字会被Nacos记录并使用
    8. name: nacos-stock
    9. cloud:
    10. nacos:
    11. discovery:
    12. # 配置Nacos所在的位置,用于注册时提交信息
    13. server-addr: localhost:8848
    14. dubbo:
    15. protocol:
    16. # port设置-1 表示当前Dubbo端口号是自动动态生成
    17. # 会自动从20880开始寻找可用的端口号,如果被占用,就递增寻找下一个,直到找到可用为止
    18. port: -1
    19. # 设置连接的名称,一般固定设置为dubbo
    20. name: dubbo
    21. registry:
    22. # 声明当前Dubbo注册到的注册中心类型和位置
    23. address: nacos://localhost:8848
    24. consumer:
    25. # 当本项目启动时,是否检查当前项目需要的所有Dubbo服务是否是可用状态
    26. # 我们设置它的值为false,表示项目启动时不检查,所需的服务是否可用
    27. check: false

    开始复制代码

    我们先将csmall-stock模块中的IStockService接口删除

    然后直接复制config\mapper\controller\service.impl四个包

    粘贴到webapi项目中

    业务逻辑层实现类需要重新导入Mapper的包来实现正确编译

    注意impl的包名也要修改->service.impl

    然后就可以删除原stock模块的src文件夹了

    下面就可以调整webapi项目的中配置路径了

    Knife4jConfiguration:

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

    MyBatisConfiguration

    1. @Configuration
    2. // MyBatis框架扫描mapper接口包的注解
    3. @MapperScan("cn.tedu.csmall.stock.webapi.mapper")
    4. public class MyBatisConfiguration {
    5. }

    下面就可以配置实现Dubbo方法提供的步骤了

    1.2.4将业务逻辑层实现类方法声明为Dubbo可调用的方法

    当前stock模块是单纯的生产者

    1. // @DubboService注解标记的业务逻辑层实现类,其中的所有方法会注册到Nacos
    2. // 其它服务在"订阅"时,就会"发现"当前项目提供的服务(业务逻辑层方法),以便后续在需要时调用
    3. @DubboService
    4. @Service
    5. @Slf4j
    6. public class StockServiceImpl implements IStockService {
    7. //内容略....
    8. }

    如果当前项目是服务的提供者(生产者)

    还需要在SpringBoot启动类上添加@EnableDubbo的注解,才能真正让Dubbo功能生效

    1. @SpringBootApplication
    2. // 如果当前项目是Dubbo的生产者,必须在当前项目的SpringBoot启动类上添加下面注解
    3. // 才能正常正确的将当前项目提供的服务注册到Nacos
    4. @EnableDubbo
    5. public class CsmallStockWebapiApplication {
    6. public static void main(String[] args) {
    7. SpringApplication.run(CsmallStockWebapiApplication.class, args);
    8. }
    9. }

    先启动nacos在启动

    再启动stockWebapi项目

    作业:

    按上面stock模块的操作

    改写cart模块的结构,以实现Dubbo生产者功能

    1.3修改cart模块

    操作步骤和stock完全一致,参考stock模块即可

    1.4修改order模块支持Dubbo

    因为order模块在Dubbo的调用关系中

    既是生产者又是消费者

    它消费cart和stock的服务

    同时又为business模块提供服务

    重构的过程和stock\cart有很多相似,但是也要注意不同

    1.4.1创建csmall-order-service项目

    这个项目创建的过程和stock\cart模块service项目的步骤和注意事项完全一致

    1.4.2创建csmall-order-webapi项目

    创建项目后父子相认正常

    子项目的pom文件依赖需要添加下面内容

    1. <dependency>
    2. <groupId>com.alibaba.cloudgroupId>
    3. <artifactId>spring-cloud-starter-dubboartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>cn.tedugroupId>
    7. <artifactId>csmall-order-serviceartifactId>
    8. <version>0.0.1-SNAPSHOTversion>
    9. dependency>
    10. <dependency>
    11. <groupId>cn.tedugroupId>
    12. <artifactId>csmall-cart-serviceartifactId>
    13. <version>0.0.1-SNAPSHOTversion>
    14. dependency>
    15. <dependency>
    16. <groupId>cn.tedugroupId>
    17. <artifactId>csmall-stock-serviceartifactId>
    18. <version>0.0.1-SNAPSHOTversion>
    19. dependency>

    yml文件配置也和cart\stock模块一致

    代码也都正常从csmall-order复制到csmall-order-webapi中

    删除csmall-order的src目录

    config包中的配置,修改为正确包名

    在OrderServiceImpl业务逻辑层实现类中

    添加生产者的注解,同时利用Dubbo消费stock和cart模块的方法

    Reference:引用

    1. // Order模块既是生产者也是消费者,所以作为生产者,还是要编写@DubboService
    2. @DubboService
    3. @Service
    4. @Slf4j
    5. public class OrderServiceImpl implements IOrderService {
    6. @Autowired
    7. private OrderMapper orderMapper;
    8. // 添加@DubboReference注解,表示当前业务逻辑层代码,要消费其它模块的服务
    9. // 可以编写当前Nacos中注册的其它模块的业务逻辑层接口
    10. // 因为在Nacos中注册的是接口的实现类,可以实现自动装配实现类的效果
    11. // 先添加stock模块的业务对象,有些公司要求dubbo引用的对象使用dubbo开头
    12. @DubboReference
    13. private IStockService dubboStockService;
    14. @DubboReference
    15. private ICartService dubboCartService;
    16. @Override
    17. public void orderAdd(OrderAddDTO orderAddDTO) {
    18. // 1.减少订单中商品的库存数(要调用stock模块的方法)
    19. // 实例化减少订单业务的DTO对象
    20. StockReduceCountDTO countDTO=new StockReduceCountDTO();
    21. countDTO.setCommodityCode(orderAddDTO.getCommodityCode());
    22. countDTO.setReduceCount(orderAddDTO.getCount());
    23. // dubbo调用stock模块减少库存数的方法
    24. dubboStockService.reduceCommodityCount(countDTO);
    25. // 2.删除订单中选中的购物车的商品(要调用cart模块的方法)
    26. dubboCartService.deleteUserCart(orderAddDTO.getUserId(),
    27. orderAddDTO.getCommodityCode());
    28. // 3.执行将orderAddDTO中的信息新增到订单表中的功能
    29. // 实例化一个Order对象
    30. Order order=new Order();
    31. BeanUtils.copyProperties(orderAddDTO,order);
    32. // 执行新增
    33. orderMapper.insertOrder(order);
    34. log.info("新增的订单信息为{}",order);
    35. }
    36. }

    因为order模块也是生产者@EnableDubbo注解仍然要写

    1. @SpringBootApplication
    2. @EnableDubbo
    3. public class CsmallOrderWebapiApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(CsmallOrderWebapiApplication.class, args);
    6. }
    7. }

    我们可以测试这个Dubbo的功能

    首先保证Nacos启动

    我们项目的启动顺序,尽量保证生产者先启动

    启动消费者

    stock\cart最后启动order

    访问

    http://localhost:20002/doc.html运行测试

    注意运行前,数据库的数据状态和运行后的比较一下

    1.5负载均衡

    1.6什么是负载均衡

    在实际项目中,一个服务基本都是集群模式的,也就是多个功能相同的项目在运行,这样才能承受更高的并发

    这时一个请求到这个服务,就需要确定访问哪一个服务器

    Dubbo框架内部支持负载均衡算法,能够尽可能的让请求在相对空闲的服务器上运行

    在不同的项目中,可能选用不同的负载均衡策略,以达到最好效果

    Loadbalance:就是负载均衡的意思

    1.7Dubbo内置负载均衡策略算法

    Dubbo内置4种负载均衡算法

    • random loadbalance:随机分配策略(默认)
    • round Robin Loadbalance:权重平均分配
    • leastactive Loadbalance:活跃度自动感知分配
    • consistanthash Loadbalance:一致性hash算法分配

    实际运行过程中,每个服务器性能不同

    在负载均衡时,都会有性能权重,这些策略算法都考虑权重问题

    1.7.1随机分配策略

    假设我们当前3台服务器,经过测试它们的性能权重比值为5:3:1

    下面可以生成一个权重模型

    随机生成随机数

    在哪个范围内让哪个服务器运行

    优点:

    算法简单,效率高,长时间运行下,任务分配比例准确

    缺点:

    偶然性高,如果连续的几个随机请求发送到性能弱的服务器,会导致异常甚至宕机

    1.7.2权重平滑分配

    如果几个服务器权重一致,那么就是依次运行

    但是服务器的性能权重一致的可能性很小

    所以我们需要权重平滑分配

    一个优秀的权重分配算法,应该是让每个服务器都有机会运行的

    如果一个集群服务器性能比为5:3:1

    1>A 2>A 3>A 4>A 5>A 6>B 7>B 8>B 9>C

    10>A

    上面的安排中,连续请求一个服务器肯定是不好的,我们希望所有的服务器都能够穿插在一起运行

    Dubbo2.7之后更新了这个算法使用"平滑加权算法"优化权重平均分配策略

    优点:

    能够尽可能的在权重要求的情况下,实现请求的穿插运行(交替运行),不会发生随机策略中的偶发情况

    缺点

    服务器较多时,可能需要减权和复权的计算,需要消耗系统资源

    1.7.3活跃度自动感知

    记录每个服务器处理一次请求的时间

    按照时间比例来分配任务数,运行一次需要时间多的分配的请求数较少

    1.7.4一致性Hash算法

    根据请求的参数进行hash运算

    以后每次相同参数的请求都会访问固定服务器

    因为根据参数选择服务器,不能平均分配到每台服务器上

    使用的也不多

    1.8修改business模块

    business模块是我们设计的新增订单业务的触发者,是起点

    它是单纯的消费者

    我们不需要像生产者一样去创建两个子项目

    直接在现有项目上进行修改即可

    pom文件直接添加dubbo和order业务逻辑接口的依赖

    1. <dependency>
    2. <groupId>com.alibaba.cloudgroupId>
    3. <artifactId>spring-cloud-starter-dubboartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>cn.tedugroupId>
    7. <artifactId>csmall-order-serviceartifactId>
    8. <version>0.0.1-SNAPSHOTversion>
    9. dependency>

    application-dev.yml添加Dubbo的配置

    1. spring:
    2. application:
    3. # 为当前项目起名,这个名字会被Nacos记录并使用
    4. name: nacos-business
    5. cloud:
    6. nacos:
    7. discovery:
    8. # 配置Nacos所在的位置,用于注册时提交信息
    9. server-addr: localhost:8848
    10. dubbo:
    11. protocol:
    12. port: -1
    13. name: dubbo
    14. registry:
    15. address: nacos://localhost:8848
    16. consumer:
    17. check: false

    我们要在当前busindess模块的业务逻辑层实现类中

    实现Dubbo调用order模块的生成订单方法

    BusinessServiceImpl类中

    1. @Service
    2. @Slf4j
    3. public class BusinessServiceImpl implements IBusinessService {
    4. // Dubbo调用order模块的新增订单的方法
    5. // 单纯的消费者,不需要在类上添加@DubboService
    6. // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    7. @DubboReference
    8. private IOrderService dubboOrderService;
    9. @Override
    10. public void buy() {
    11. // 模拟购买业务
    12. // 创建用于新增订单的DTO实体OrderAddDTO
    13. OrderAddDTO orderAddDTO=new OrderAddDTO();
    14. // 为orderAddDTO赋值
    15. orderAddDTO.setUserId("UU100");
    16. orderAddDTO.setCommodityCode("PC100");
    17. orderAddDTO.setCount(10);
    18. orderAddDTO.setMoney(666);
    19. // 因为是模拟购买,现在还不能调用order模块,所以只是输出
    20. log.info("新增订单的信息为:{}",orderAddDTO);
    21. // dubbo调用业务
    22. // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    23. dubboOrderService.orderAdd(orderAddDTO);
    24. }
    25. }

    Springboot启动类不必要写@EnableDubbo因为business是单纯的消费者

    启动business项目(前提是cart\stock\order正在运行)

    http://localhost:20000/doc.html运行测试

    1.9Dubbo生产者消费者配置小结

    Dubbo生产者消费者相同的配置

    pom文件添加dubbo依赖,yml文件配置dubbo信息

    1.9.1生产者

    • 要有service接口项目

    • 提供服务的业务逻辑层实现类要添加@DubboService注解

    • SpringBoot启动类要添加@EnableDubbo注解

    1.9.2消费者

    • pom文件添加消费模块的service依赖
    • 业务逻辑层远程调用前,模块使用@DubboReference注解获取业务逻辑层实现类对象

    2.Seata概述

    2.1下载Seata

    Releases · seata/seata · GitHub

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

    最好能从项目经理老师处获取

    2.2什么是Seata

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

    也是Spring Cloud Alibaba提供的组件

    Seata官方文档

    Seata

    更多信息可以通过官方文档获取

    2.3为什么需要Seata

    我们之前学习了单体项目中的事务

    使用的技术叫Spring声明式事务

    能够保证一个业务中所有对数据库的操作要么都成功,要么都失败,来保证数据库的数据完整性

    但是在微服务的项目中,业务逻辑层涉及远程调用,当前模块发生异常,无法操作远程服务器回滚

    这时要想让远程调用也支持事务功能,就需要使用分布式事务组件Seata

    事务的4个特性:ACID特性

    • 原子性
    • 一致性
    • 隔离性
    • 永久性

    Seata保证微服务远程调用业务的原子性

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

    2.4Seata的运行原理(AT模式)

    观察下面事务模型

    上面结构是比较典型的远程调用结构

    如果account操作数据库失败需要让order模块和storage模块撤销(回滚)操作

    声明式事务不能完成这个操作

    需要使用Seata来解决

    Seata构成部分包含

    • 事务协调器TC
    • 事务管理器TM
    • 资源管理器RM

    我们项目使用AT(自动)模式完成分布式事务的解决

    AT模式运行过程

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

    2.Seata会管理事务中所有相关的参与方的数据源,将数据操作之前和之后的镜像都保存在undo_log表中,这个表是seata组件规定的表,没有它就不能实现效果,依靠它来实现提交(commit)或回滚(roll back)的操作

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

    4.RM接收到全局id,去运行指定方法,并将运行结果的状态发送给TC

    5.如果所有分支运行都正常,事务管理器(TM)会通过事务协调器通知所有模块执行数据库操作,真正影响数据库内容,反之如果有任何一个分支模块运行异常,都会通知TC,再由TC通知所有分支将数据库操作回滚,恢复成运行之前的样子

    2.5Seata的启动

    seata也是java开发的,启动方式和nacos很像

    只是启动命令不同

    它要求配置环境变量中Path属性值有java的bin目录路径

    解压后路径不要用中文,不要用空格

    也是解压之后的bin目录下

    在路径上输入cmd进入dos窗口

    D:\tools\seata\seata-server-1.4.2\bin>seata-server.bat -h 127.0.0.1 -m file
    

    输入后,最后出现8091端口的提示即可!

  • 相关阅读:
    如何在Linux(CentOS)中添加tree命令------包括用户不在sudoers文件中的解决方法
    网络安全(黑客)自学
    ide 快捷键
    Leetcode139. 单词拆分
    微信小程序与Netty实现的WebSocket聊天程序
    前端注释工具的优雅使用指南
    第三章 内存管理 一、内存的基础知识
    DataBaseHelper sqlsugar
    git 创建分支并提交
    SylixOS 版本与 RealEvo-IDE 版本对应关系说明
  • 原文地址:https://blog.csdn.net/TheNewSystrm/article/details/126490782