微服务09-Seata续/Sentinel/SpringGateway网关

目录

Seata续

seata的启动

使用Seata

配置Seata

Seata其他模式介绍

TCC模式

SAGA模式

XA模式

Sentinel

什么是Sentinel

为什么需要Sentinel

基本配置

Sentinel启动

限流方法

自定义限流方法

QPS与并发线程数

自定义降级方法

SpringGateway网关

奈非框架简介

什么是网关

Spring Gateway简介

简单网关演示

随笔


Seata续

seata的启动

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

只是启动命令不同

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

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

也是解压之后的bin目录下

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

mac系统直接参考启动nacos的命令

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

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

如果想使用idea启动seata,和之前nacos启动相似

使用Seata

配置Seata

cart\stock\order三个模块时需要Seata支持进行事务管理的模块

这三个模块都需要添加下面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>

下面修改cart\stock\order模块的application-dev.yml

代码如下

seata:
  tx-service-group: csmall_group # 定义事务分组名称,一般是以项目为单位的,可以与其他项目区分
  service:
    vgroup-mapping:
      csmall_group: default      # csmall_group分组使用Seata默认的配置完成事务
    grouplist:
      default: localhost:8091    # 配置Seata服务器的地址和端口号信息(8091是默认端口号)

注意同一个事务必须在同一个tx-service-group中

同时指定相同的seata地址和端口

business模块的配置

business模块作为当前分布式事务模型的触发者

它应该是事务的起点,但是它不连接数据库,所以配置稍有不同

pom文件seata依赖仍然需要,但是只需要seata依赖

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
</dependency>

application-dev.yml是一样的

seata:
  tx-service-group: csmall_group  # 定义分组名称,为了与其它项目区分
  service:
    vgroup-mapping:
      csmall_group: default       # csmall_group分组使用Seata的默认配置完成事务  
    grouplist: 
      default: localhost:8091     # 配置seata的地址和端口号(8091是默认端口号)

添加完必要的配置之后

要想启动Seata非常简单,只要在起点业务的业务逻辑方法上添加专用的注解即可

添加这个注解的模块就是模型中的TM

他调用的所有远程模块都是RM

business模块添加订单的业务逻辑层开始的方法

@Service
@Slf4j
public class BusinessServiceImpl implements IBusinessService {

    // Dubbo调用Order模块的新增订单功能
    // Business是单纯的消费者,不需要在类上编写@DubboService
    @DubboReference
    private IOrderService dubboOrderService;

    // Global全局,Transactional事务
    // 一旦一个方法上标记的@GlobalTransactional注解
    // 就相当于设置了分布式事务的起点,当前模块就是分布式事务模型中的TM
    // 最终效果就是当前方法开始,之后所有的远程调用操作数据库的结果就会实现事务的特征
    // 也就是说要么都执行,要么都不执行
    @GlobalTransactional
    @Override
    public void buy() {
		 //  代码略...
    }
}

先启动Nacos,在seata不关闭的前提下

再启动所有4个服务cart\stock\order\business

利用knife4j访问business模块,否则无法触发事务效果,business模块是seata事务的起点

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

根据是否发生随机异常,来判断seata是否有效

OrderServiceImpl在新增订单方法前添加随机发送异常的方法

@Override
public void orderAdd(OrderAddDTO orderAddDTO) {
    // 1.减少订单中商品的库存数(要调用stock模块的功能)
    // 实例化减少库存业务的DTO对象
    StockReduceCountDTO countDTO=new StockReduceCountDTO();
    countDTO.setCommodityCode(orderAddDTO.getCommodityCode());
    countDTO.setReduceCount(orderAddDTO.getCount());
    // 执行dubbo调用完成stock模块减少库存的方法
    dubboStockService.reduceCommodityCount(countDTO);
    // 2.从购物车中删除订单中选择中的商品(要调用cart模块的功能)
    dubboCartService.deleteUserCart(orderAddDTO.getUserId(),
                                    orderAddDTO.getCommodityCode());
	// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    if(Math.random()<0.5){
        throw new CoolSharkServiceException(
                ResponseCode.INTERNAL_SERVER_ERROR,"随机异常!");
    }

    // 3.将orderAddDTO中的信息新增到数据库订单表中
    // 要将orderAddDTO对象中的属性赋值给Order类型对象的同名属性
    Order order=new Order();
    BeanUtils.copyProperties(orderAddDTO,order);
    // 执行新增
    orderMapper.insertOrder(order);
    log.info("新增订单信息为:{}",order);
}

如果seata启动时发送内存不足的错误,可以参考下面的文章解决

springCloud框架搭建(五)使用seata分布式事务_he_lei的博客-CSDN博客_springcloud 使用seata

业务逻辑层接口添加 @GlobalTransactional注解的效果我们可以自己去尝试

启动服务时,经常见到Dubbo报错

Dubbo报错处理

报错信息特别长的

  • 删除nacos配置列表中的所有信息(可以先选每页显示100条,在执行全删)

    然后停掉所有服务重启

  • consumer:
      # 当本项目启动时,是否检查当前项目需要的所有Dubbo服务是否是可用状态
      # 我们设置它的值为false,表示项目启动时不检查,所需的服务是否可用
      check: false
      timeout: 50000
    
  • 报错信息特别长,但是不影响运行的

    是因为当前计算机wifi网卡配置或防火墙软件导致的,可以无视

Seata其他模式介绍

上一节我们讲解了Seata软件AT模式的运行流程

AT模式的运行有一个非常明显的前提条件,这个条件不满足,就无法使用AT模式

这个条件就是事务分支都必须是操作关系型数据库(Mysql\MariaDB\Oracle)

因为关系型数据库才支持提交和回滚,其它非关系型数据库都是直接影响数据(例如Redis)

所以如果我们在业务过程中有一个节点操作的是Redis或其它非关系型数据库时,就无法使用AT模式

除了AT模式之外还有TCC、SAGA 和 XA 事务模式

TCC模式

简单来说,TCC模式就是自己编写代码完成事务的提交和回滚

在TCC模式下,我们需要为参与事务的业务逻辑编写一组共3个方法

(prepare\commit\rollback)

prepare:准备

commit:提交

rollback:回滚

  • prepare方法是每个模块都会运行的方法
  • 当所有模块的prepare方法运行都正常时,运行commit
  • 当任意模块运行的prepare方法有异常时,运行rollback

这样的话所有提交或回滚代码都由自己编写

优点:虽然代码是自己写的,但是事务整体提交或回滚的机制仍然可用(仍然由TC来调度)

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

SAGA模式

SAGA模式的思想是对应每个业务逻辑层编写一个新的类,可以设置指定的业务逻辑层方法发生异常时,运行当新编写的类中的代码

相当于将TCC模式中的rollback方法定义在了一个新的类中

这样编写代码不影响已经编写好的业务逻辑代码

一般用于修改已经编写完成的老代码

缺点是每个事务分支都要编写一个类来回滚业务,

会造成类的数量较多,开发量比较大

XA模式

支持XA协议的数据库分布式事务,使用比较少

Sentinel

官网地址

home

下载地址

Releases · alibaba/Sentinel · GitHub

什么是Sentinel

Sentinel英文翻译"哨兵\门卫"

Sentinel也是Spring Cloud Alibaba的组件

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

为什么需要Sentinel

为了保证服务器运行的稳定性,在请求数到达设计最高值时,将过剩的请求限流,保证在设计的请求数内的请求能够稳定完成处理

  • 丰富的应用场景

    双11,秒杀,12306抢火车票

  • 完备的实时状态监控

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

  • 广泛的开源生态

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

  • 完善的SPI扩展

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

基本配置

我们的限流针对的是控制器方法

我们找一个简单的模块来测试和观察限流效果

在csmall-stock-webapi模块中

添加sentinel的依赖

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

application-dev.yml文件添加配置

spring:
  application:
    #  为当前项目起名,这个名字会被Nacos记录并使用
    name: nacos-stock
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 # 配置sentinel的位置(运行状态仪表盘)
        # 执行限流的端口号,每个项目都不同(别的项目例如cart模块,要再向设置限流就不能用8721了)
        port: 8721
    nacos:
      discovery:
        # 配置Nacos所在的位置,用于注册时提交信息
        server-addr: localhost:8848

Sentinel启动

windows直接双击start-sentinel.bat文件

mac使用下面命令执行jar包

java -jar sentinel-dashboard-1.8.2.jar

启动之后

打开浏览器http://localhost:8080/

会看到下面的界面

用户名和密码都是

sentinel

刚开始什么都没有,是空界面

后面我们有控制器的配置就会出现信息了

限流方法

我们以stock模块为例

演示限流的效果

StockController在减少库存的方法上添加限流的注解

@PostMapping("/reduce/count")
@ApiOperation("减少商品库存数")
// @SentinelResource注解要标记控制层的方法才能生效,会在该方法运行时,被Sentinel管理
// 这个控制器方法第一次运行后,会在Sentinel仪表台中看到限流选项
// "减少商品库存数",会定义仪表台中代表该方法的选项名称
@SentinelResource("减少商品库存数")
public JsonResult reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO){
    // 调用业务逻辑层
    stockService.reduceCommodityCount(stockReduceCountDTO);
    return JsonResult.ok("库存减少已执行");
}

nacos\seata\sentinel要启动

重启stock服务(其它服务都可以停掉)

如果不运行knife4j测试,sentinel的仪表盘不会有任何信息

在第一次运行了减少库存方法之后,sentinel的仪表盘才会出现nacos-stock的信息

选中这个信息点击"簇点链路"

找到我们编写的"减少商品库存数"方法,点 "+流控"

设置流控规则

我们先设置QPS为1也就是每秒请求数超过1时,进行限流

然后我们可以快速双击knife4j减少库存的方法,触发它的流控效果

这样的流控没有正确的消息提示

我们需要自定义方法进行正确的提示给用户看到

自定义限流方法

对于被限流的请求,我们可以自定义限流的处理方法

默认情况下可能不能正确给用户提示,一般情况下,对被限流的请求也要有"服务器忙请重试"或类似的提示

StockController类中@SentinelResource注解中,可以自定义处理限流情况的方法

@PostMapping("/reduce/count")
@ApiOperation("减少商品库存数")
// @SentinelResource注解要标记控制层的方法才能生效,会在该方法运行时,被Sentinel管理
// 这个控制器方法第一次运行后,会在Sentinel仪表台中看到限流选项
// "减少商品库存数",会定义仪表台中代表该方法的选项名称
// blockHandler能够指定当前方法被限流时运行的方法名称
@SentinelResource(value = "减少商品库存数",blockHandler = "blockError")
public JsonResult reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO){
    // 调用业务逻辑层
    stockService.reduceCommodityCount(stockReduceCountDTO);
    return JsonResult.ok("库存减少已执行");
}

// Sentinel 自定义限流方法,规则如下
// 1.访问修饰符必须是public
// 2.返回值类型必须和控制器方法一致
// 3.方法名必须和对应的限流控制器方法定义的blockHandler属性值一致
// 4.方法的参数列表必须和控制器一致,而且还要额外添加BlockException类型的参数
public JsonResult blockError(StockReduceCountDTO stockReduceCountDTO,
                             BlockException e){
    // 运行这个方法就是被限流了,直接返回被限流的提示即可
    return JsonResult.failed(ResponseCode.INTERNAL_SERVER_ERROR,
                        "服务器忙,请稍后再试");
}

重启stock-webapi模块

再次尝试被限流,观察被限流的提示

QPS与并发线程数

  • QPS:是每秒请求数

    单纯的限制在一秒内有多少个请求访问控制器方法

  • 并发线程数:是当前正在使用服务器资源请求线程的数量

    限制的是使用当前服务器的线程数

自定义降级方法

所谓降级就是正常运行控制器方法的过程中

控制器方法发生了异常,Sentinel支持我们运行别的方法来处理异常,或运行别的业务流程处理

我们也学习过处理控制器异常的统一异常处理类,和我们的降级处理有类似的地方

但是Sentinel降级方法优先级高,而且针对单一控制器方法编写

StockController类中@SentinelResource注解中,可以定义处理降级情况的方法

@PostMapping("/reduce/count")
@ApiOperation("减少商品库存数")
// @SentinelResource注解要标记控制层的方法才能生效,会在该方法运行时,被Sentinel管理
// 这个控制器方法第一次运行后,会在Sentinel仪表台中看到限流选项
// "减少商品库存数",会定义仪表台中代表该方法的选项名称
// blockHandler能够指定当前方法被限流时运行的方法名称
@SentinelResource(value = "减少商品库存数",blockHandler = "blockError",
                  fallback = "fallbackError")
public JsonResult reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO){
    // 测试Sentinel服务降级的随机异常
    if(Math.random()<0.5){
        // 如果发生异常,会运行服务降级的方法
        throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,
                                            "随机异常");
    }
    // 调用业务逻辑层
    stockService.reduceCommodityCount(stockReduceCountDTO);
    return JsonResult.ok("库存减少已执行");
}

// Sentinel 自定义限流方法略....


// 降级方法:上面@SentinelResource中fallback指定的降级方法
// 声明格式:和限流方法基本相同,方法参数不需要添加异常类型
// 当控制器方法发生异常时,Sentinel会自动调用这个方法
// 在实际业务中,可以是运行新版本代码的过程中发送异常后,转而运行老版本代码的机制
public JsonResult fallbackError(StockReduceCountDTO stockReduceCountDTO){
    // 因为没有老版本代码,所以这里仅仅是输出降级提示
    return JsonResult.failed(ResponseCode.INTERNAL_SERVER_ERROR,
                             "运行发生异常,服务降级");
}

重启csmall-stock-webapi模块测试

当发生随机异常时,就运行降级方法

当没有发生随机异常时,就正常运行!

SpringGateway网关

奈非框架简介

早期(2020年前)奈非提供的微服务组件和框架受到了很多开发者的欢迎

这些框架和SpringCloud Alibaba的对应关系我们要了解

现在还有很多旧项目维护是使用奈非框架完成的微服务架构

Nacos对应Eureka都是注册中心

Dubbo对应Ribbon+feign都是实现微服务远程RPC调用的组件

Sentinel对应Hystrix都是做项目限流熔断降级的组件

Gateway对应Zuul都是网关组件

Gateway框架不是阿里写的,是Spring提供的

什么是网关

"网"指网络,"关"指关口或关卡

网关:就是指网络中的关口\关卡

网关就是当前微服务项目的"统一入口"

程序中的网关就是当前微服务项目对外界开放的统一入口

所有外界的请求都需要先经过网关才能访问到我们的程序

提供了统一入口之后,方便对所有请求进行统一的检查和管理

网关的主要功能有

  • 将所有请求统一经过网关
  • 网关可以对这些请求进行检查
  • 网关方便记录所有请求的日志
  • 网关可以统一将所有请求路由到正确的模块\服务上

路由的近义词就是"分配"

Spring Gateway简介

我们使用Spring Gateway作为当前项目的网关框架

Spring Gateway是Spring自己编写的,也是SpringCloud中的组件

SpringGateway官网

Spring Cloud Gateway

简单网关演示

SpringGateway网关是一个依赖,不是一个软件

所以我们要使用它的话,必须先创建一个SpringBoot项目

这个项目也要注册到Nacos注册中心,因为网关项目也是微服务项目的一个组成部分

beijing和shanghai是编写好的两个项目

gateway项目就是网关项目,需要添加相关配置

<dependencies>
    <!--   Gateway依赖   -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!--   Nacos依赖   -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--   网关负载均衡依赖    -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
</dependencies>

我们从yml文件配置开始添加

server:
  port: 9000
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 网关也是微服务项目的一部分,所以也要注册到Nacos
        server-addr: localhost:8848
    gateway:
      # routes就是路由的意思,在此处配置是一个数组类型
      routes:
        # 数组类型中编写 "-"开头,表示是一个数组元素
        # id表示当前路由的名称,没有和其他任何出现过的名字关联,和之后的内容也没有关联
        - id: gateway-beijing
          # 当前路由配置的路由目标配置,也就是路由路径
          # lb是LoadBalance的缩写,beijing是路由目标服务器的名称
          uri: lb://beijing
          # 下面编写路由条件\规则,也就是满足什么样的路径会访问beijing服务器
          # 我们要配置内置断言来配置路径路径   predicates(断言)
          predicates:
            # 断言其实就是满足某个条件时做什么操作的设置
            # predicates和routes类似,也是一个数组类型
            # ↓  P大写!!!!!  表示以/bj/开头的请求都会路由到beijing服务器
            - Path=/bj/**
# spring.cloud.gateway.routes[0].uri
# spring.cloud.gateway.routes[0].predicates[0]

随笔

路由规则解释

路由规则一定是在开发之前就设计好的

一般可以使用约定好的路径开头来实现的

例如

gateway项目

如果路径以 /bj开头,就是要访问beijing项目

如果路径以 /sh开头.就是养访问shanghai项目

csmall项目

如果路径是 /base/business开头的, 就去找nacos-business服务器

如果路径是 /base/cart开头的, 就去找nacos-cart服务器

如果路径是 /base/order开头的, 就去找nacos-order服务器

如果路径是 /base/stock开头的, 就去找nacos-stock服务器

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值