SpringCloud 2020笔记三

Spring Cloud 2020 笔记二

八、Spring Cloud Stream

  • 构建消息驱动微服务的框架
  • 应用程序通过生产者(outputs)、消费者(inputs)与Spring Cloud Stream中binder对象交互
  • 通过在配置文件中进行配置来binding,而Spring Cloud Stream的binder对象负责与消息中间件交互
  • 类似jpa,屏蔽底层消息中间件的差异,程序员主要操作Spring Cloud Stream即可
  • 不需要管底层是kafka还是rabbitMq,屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型

1、如何屏蔽差异(Rabbit MQ、KafKa)

  • 通过定义帮定器Binder作为中间层,实现了应用程序与消息中间件细节之间的隔离
  • Binder:INPUT对应消费者,OUTPUT对应生产者

2、处理架构

在这里插入图片描述

3、通信模式

  • 遵循发布-订阅模式
  • Topic主题进行广播:在Rabbit中是exchange、kafka中是Topic

4、业务流程

在这里插入图片描述

5、常用注解及API

在这里插入图片描述

6、实操

(1)pom依赖
  • 生产者与消费者添加的依赖相同
<!-- cloud stream 相关依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
(2)yml配置
spring:
  cloud:
    stream:
      binders: # 配置要绑定的mq的服务信息
        streamRabbit:       # 自定义的名称,用于binding整合
          type: rabbit      # mq类型,rabbitmq / kafka
          environment:      # mq环境配置信息
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
        outPutOneRabbit: # 自定义的名称,用于binding整合
          type: rabbit      # mq类型,rabbitmq / kafka
          environment: # mq环境配置信息
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
        outPutTwoRabbit: # 自定义的名称,用于binding整合
          type: rabbit      # mq类型,rabbitmq / kafka
          environment: # mq环境配置信息
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings:   # 服务整合处理
        output:   # 一个通道的名称,默认为output,可自定义
          destination: streamRabbitExchange   # rabbitmq中使用的exchange
          content-type: application/json      # 消息类型
          binder: streamRabbit                # 设置要绑定的消息服务的具体设置,与binders中的一一对应
        myOutPutOne: # 一个通道的名称,默认为output,可自定义
          destination: streamRabbitOneExchange   # rabbitmq中使用的exchange
          content-type: application/json      # 消息类型
          binder: outPutOneRabbit                # 设置要绑定的消息服务的具体设置,与binders中的一一对应
        myOutPutTwo: # 一个通道的名称,默认为output,可自定义
          destination: streamRabbitOneExchange   # rabbitmq中使用的exchange
          content-type: application/json      # 消息类型
          binder: outPutTwoRabbit                # 设置要绑定的消息服务的具体设置,与binders中的一一对应
          
        input: # 一个通道的名称,默认为output,可自定义
          destination: streamRabbitExchange   # rabbitmq中使用的exchange
          content-type: application/json      # 消息类型
          binder: streamRabbit                # 设置要绑定的消息服务的具体设置,与binders中的一一对应
          group: groupOne
        myInputOne: # 一个通道的名称,默认为output,可自定义
          destination: streamRabbitOneExchange   # rabbitmq中使用的exchange
          content-type: application/json      # 消息类型
          binder: outPutOneRabbit                # 设置要绑定的消息服务的具体设置,与binders中的一一对应
          group: groupInputOne
        myInputTwo: # 一个通道的名称,默认为output,可自定义
          destination: streamRabbitTwoExchange   # rabbitmq中使用的exchange
          content-type: application/json      # 消息类型
          binder: outPutTwoRabbit                # 设置要绑定的消息服务的具体设置,与binders中的一一对应
          group: groupInputTwo
      default-binder: streamRabbit
(3)配置解析
  • binders:配置要绑定的mq的服务信息
  • streamRabbit:自定义的名称,需要保持唯一性,在bindings中整合
  • type:mq类型
  • environment:mq环境配置
  • 配置了多个mq时,需要指定一个默认的mq(default-binder),否则会报异常
  • bindings:mq服务整合
  • output:默认的生产者消息发送通道
  • input:默认的消费者消息接受通道
  • myOutPutOne、myOutPutOne:自定义的生产者消息发送通道
  • myInputOne、myInputTwo:自定义的消费者消息消费通道
  • destination:rabbitmq中的exchange
  • content-type:消息数据类型
  • binder:绑定一个mq,即binders下的streamRabbit
  • group:消费者分组,绑定了同一个mq的消费者,如果不指定分组,多个消费者会重复接受消息,且指定分组后,如果消费者宕机,消费者重新上线后可继续接收未消费的消息;
(4)自定义生产、消费通道

① 生产者

  • 是一个接口
  • 每个通道定义一个方法:MessageChannel 类型
  • 方法上加@Output注解,value为通道名称
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.stereotype.Component;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/14 16:21
 **/
public interface MyOutPutConfig {

    String myOutPutOne = "myOutPutOne";

    String myOutPutTwo = "myOutPutTwo";

    /**
     * 自定义输出
     * @return
     */
    @Output(value = myOutPutOne)
    MessageChannel myOutPutOne();

    /**
     * 自定义输出
     * @return
     */
    @Output(value = myOutPutTwo)
    MessageChannel myOutPutTwo();
}

② 消费者

  • 是一个接口
  • 每个通道定义一个方法:SubscribableChannel 类型
  • 方法加@Input注解,value为通道名称
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.stereotype.Component;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/14 16:23
 **/
public interface MyInputConfig {

    String myInputOne = "myInputOne";

    String myInputTwo = "myInputTwo";

    /**
     * 自定义接收
     * @return
     */
    @Input(value = myInputOne)
    SubscribableChannel myInputOne();

    /**
     * 自定义接收
     * @return
     */
    @Input(value = myInputTwo)
    SubscribableChannel myInputTwo();
}
(5)生产者消息发送
  • @EnableBinding 绑定自定义的通道
import com.atguigu.springcloud.config.MyOutPutConfig;
import com.atguigu.springcloud.service.IMessageSendMyOutPut;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/14 17:01
 **/
@EnableBinding(MyOutPutConfig.class)
@Slf4j
public class MessageSendMyOutPutImpl implements IMessageSendMyOutPut {

    @Autowired
    private MyOutPutConfig outPutConfig;


    @Override
    public String sendMsgByOutPutOne() {
        String now = "outPutOne ==> " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        Message<String> message = MessageBuilder.withPayload(now).build();
        outPutConfig.myOutPutOne().send(message);
        return now;
    }

    @Override
    public String sendMsgByOutPutTwo() {
        String now = "outPutTwo ==> " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        Message<String> message = MessageBuilder.withPayload(now).build();
        outPutConfig.myOutPutOne().send(message);
        return now;
    }
}
(6)消费者消息接收
import com.atguigu.springcloud.config.MyInputConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/14 17:04
 **/
@Component
@Slf4j
@EnableBinding(MyInputConfig.class)
public class ReceiveMyInput {

    @Value("${server.port}")
    private String serverPost;

    /**
     * 自定义消息接收
     * @param message
     */
    @StreamListener(MyInputConfig.myInputOne)
    public void getMsgByInputOne(Message<String> message){
        log.info(message.getPayload() + " <== inputOne ==>" + serverPost);
    }

    /**
     * 自定义消息接收
     * @param message
     */
    @StreamListener(MyInputConfig.myInputTwo)
    public void getMsgByInputTwo(String message){
        log.info(message + " <== inputTwo ==>" + serverPost);
    }
}

九、链路追踪:Spring Cloud Sleuth

  • 用于追踪每个请求的整体链路
  • 需要安装zipkin:可直接运行jar包,使用web页面查看链路数据,默认地址为: localhost:9411
  • 项目中如何使用:
    • 在需要被监控的微服务中添加依赖:
    <!--包含了sleuth+zipkin-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    
    • yml中添加配置
    spring:
      application:
        name: cloud-order-service
      zipkin:
        base-url: http://localhost:9411
      sleuth:
        sampler:
          #采样率值介于0到1之间,1则表示全部采集
          probability: 1
    
    • 调用接口之后可在web界面查看到链路信息

十、Spring Cloud Alibaba — Nacos

1、是什么

  • 阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台
  • 是服务注册和配置中心的组合

2、安装

  • 下载地址:github
  • 下载解压后进入bin目录,windows运行start.cmd,linux运行start.sh
  • Nacos默认端口为8848,localhost:8848/nacos,账号密码默认都为nacos

3、在微服务中使用nacos(作为服务注册中心)

在这里插入图片描述

3.1 服务提供
  • Spring Cloud Alibaba 依赖
<dependencyManagement>
	 <dependencies>
	     <dependency>
	         <groupId>com.alibaba.cloud</groupId>
	         <artifactId>spring-cloud-alibaba-dependencies</artifactId>
	         <version>2.1.0.RELEASE</version>
	         <type>pom</type>
	         <scope>import</scope>
	     </dependency>
	 </dependencies>
</dependencyManagement>
  • Nacos依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • yml配置文件
server:
  port: 9001

spring:
  application:
    name: cloud-alibaba-nacos-provider
  cloud:
    nacos:
      discovery:
      	# nacos 地址
        server-addr: localhost:8848
        
management:
  endpoints:
    web:
      exposure:
        include: '*'
  • 启动类添加注解@EnableDiscoveryClient
3.2 服务消费
  • pom文件添加的依赖和服务提供方一样
  • yml配置文件
server:
  port: 83

spring:
  application:
    name: cloud-albaba-nacos-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:1111
# 消费者使用RestTemplate远程调用的服务提供方地址
service:
  provider-url: http://cloud-alibaba-nacos-provider
  • 启动类添加注解 @EnableDiscoveryClient
  • 负载均衡,因为Nacos集成了Ribbon所以Nacos也支持负载均衡,需要添加配置类开启
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;

/**
 * @create 2022-01-14
 */
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

4、Nacos与其他服务注册对比

在这里插入图片描述

  • Nacos 既支持CP,也支持AP,通过curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'切换CP、AP模式
    在这里插入图片描述

5、在微服务中使用Nacos(作为配置中心)

在这里插入图片描述

  • 和Spring Cloud Config 一样,在项目初始化时,要保证先从配置中心进行配置拉取,只有在拉取配置之后,才能保证项目的正常启动
  • Spring Boot 中配置文件的加载存在优先级顺序,bootstrap优先级高于application
5.1、如何使用
  • 作为配置中心所需依赖
<!--nacos-config 配置中心-自带动态刷新-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<!--nacos-discovery 注册中心-服务发现与注册-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • bootstrap.yml
server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848#服务注册中心地址
      config:
        server-addr: localhost:8848 #配置中心地址
        file-extension: yaml #指定yaml格式的配置

# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
# nacos-config-client-dev.yaml
# nacos-config-client-test.yaml   ----> config.info
  • application.yml
spring:
  profiles:
    active: dev
  • 启动类添加注解 @EnableDiscoveryClient
  • controller:在类级别上添加 @RefreshScope 注解,用于自动刷新
5.2、配置文件命名规则(dataid)

${spring.application.name}-${spring.profiles.active}-${spring.cloud.nacos.config-file-extension}

  • ${spring.application.name}:微服务应用名称
  • ${spring.profiles.active}:开发环境(dev、test、prod)
  • ${spring.cloud.nacos.config-file-extension}:文件类型(yaml、properties)
5.3、自动刷新
  • Nacos支持Bus总线,在Nacos的web页面修改配置文件后,会自动发送命令更新所有客户端
  • 需要在controller添加类级别注解 @RefreshScope
5.4、分类配置

在这里插入图片描述

NameSpace + Group + DataID,类似Java中的package + class + method

  • NameSpace:命名空间,默认为public
    在这里插入图片描述

  • Group:分组,在Nacos的web界面新建配置文件时创建,默认为DEFAULT_GROUP

  • DataID:配置文件名称,根据命名规则命名

6、Nacos集群及持久化配置

6.1 切换Nacos自带数据库为我们自己的MySQL数据库
  • 在Nacos的conf目录下找到application.properties配置文件,并修改配置
# spring

server.contextPath=/nacos
server.servlet.contextPath=/nacos
# nacos端口,可根据实际情况进行修改
server.port=8848

# nacos.cmdb.dumpTaskInterval=3600
# nacos.cmdb.eventTaskInterval=10
# nacos.cmdb.labelTaskInterval=300
# nacos.cmdb.loadDataAtStart=false


# metrics for prometheus
#management.endpoints.web.exposure.include=*

# metrics for elastic search
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200

# metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true

server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i
# default current work dir
server.tomcat.basedir=

## spring security config
### turn off security
#spring.security.enabled=false
#management.security=false
#security.basic.enabled=false
#nacos.security.ignore.urls=/**

nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health/**,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**,/v1/console/server/**

# nacos.naming.distro.taskDispatchPeriod=200
# nacos.naming.distro.batchSyncKeyCount=1000
# nacos.naming.distro.syncRetryDelay=5000
# nacos.naming.data.warmup=true
# nacos.naming.expireInstance=true

nacos.istio.mcp.server.enabled=false

# 将nacos内嵌的derby数据库切换为自己的mysql数据库
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false
db.user=root
db.password=123456
6.2、集群部署

在这里插入图片描述

  • VIP:虚拟IP(Virtual IP)
  • Nacos默认有自带的嵌入式数据库(derby),如果是集群模式,需要使用MySQL(目前只支持MySQL)集中式存储配置信息
  • 新建MySQL数据库(nacos-config)在conf目录下找到nacos-mysql.sql,复制sql脚本在nacos-config数据库运行
  • 拷贝三份Nacos,并根据6.1修改端口号以及数据库(数据库需要一致)
    在这里插入图片描述
  • 找到Nacos安装目录下的cluster.conf,并添加Nacos集群的ip
    在这里插入图片描述
192.168.182.1:8848
192.168.182.1:8849
192.168.182.1:8850
  • 在bin目录下找到start.cmd,修改MODEcluster,表示集群模式,单体模式时,MODE值为standalone
    在这里插入图片描述
  • 使用Nginx作为VIP,添加配置
    在这里插入图片描述
  • 集群部署验证

1、先启动Nacos
2、启动Nginx
3、用浏览器访问:localhost:1111/nacos
4、可以进入nacos的web界面则表示成功

十一、Spring Cloud Alibaba — Sentinel

1、是什么

  • 实现服务熔断和限流
    在这里插入图片描述

2、运行Sentinel

  • 下载jar包,使用java -jar xxxx.jar 运行
  • 访问sentinel,端口默认为8080,localhost:8080,账号密码默认为sentinel

3、微服务整合Sentinel

  • Spring Cloud Alibaba的依赖‘
<dependencyManagement>
	 <dependencies>
	     <dependency>
	         <groupId>com.alibaba.cloud</groupId>
	         <artifactId>spring-cloud-alibaba-dependencies</artifactId>
	         <version>2.1.0.RELEASE</version>
	         <type>pom</type>
	         <scope>import</scope>
	     </dependency>
	 </dependencies>
</dependencyManagement>
  • 需要的依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  • yml配置文件
server:
  port: 8401
spring:
  application:
    name: cloud-alibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:1111
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'
  • 启动类添加注解@EnableDiscoveryClient

4、微服务整合完成并启动后,在sentinel的web界面控制台还看不到微服务的任务信息,因为sentinel是懒加载,所以需要访问微服务中的某个接口后,才能在sentinel的web界面控制台看到微服务的信息

在这里插入图片描述

4.1、流控规则

流量限制控制规则

在这里插入图片描述

  • 资源名:唯一名称,默认请求路径
  • 针对来源:可以针对调用者进行限流,填写微服务名称;默认是default(不区分来源)
  • 阈值类型:
    • QPS(每秒钟的请求数量):当调用该api的QPS达到单机阈值设定的数量时,进行限流
    • 线程数:当调用该api的线程数量达到单机阈值设定的数量后进行限流
  • 是否集群
  • 流控模式:
    • 直接:api达到限流条件时直接进行限流(没得商量)
    • 关联:关联的资源达到阈值时,就限流自己(选择该项时,需要指定关联的资源–请求路径)
    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值就进行限流)【api级别的针对来源】,当选择该项时需要指定入口资源
  • 流控效果:
    • 快速失败:直接失败,抛出异常
    • Warm up(预热):比如设置的单机阈值是10,开启了Warm up 后,实际上默认的阈值为 单机阈值 / 3(即 10 / 3 = 3),当该资源达到了阈值后,经过设定的预热时长(秒)后单机阈值才会慢慢提升到我们填写的阈值;这样做的目的是平常某些系统可能QPS不高,但是某些时间段可能或瞬间有很多的访问量,如果不设置预热,瞬间的高并发可能会导致系统崩溃的问题
    • 排队等待:匀速排队,让请求以均匀的速度通过,阈值类型必需设置为QPS,否则无效;当达到了限流条件后,新的请求需要等待设定的超时时间(毫秒)以后,才能正常访问;
4.2、降级规则

熔断降级,
(1) sentinel 会在调用链路中某个资源出现不稳定状态时(例如调用超时或者异常比例升高),对这个资源进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误;
(2)当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认是抛出DegradeException);
(3)Sentinel的断路器没有半开状态,半开状态是指系统会自动检测请求是否有异常,如果没有则关闭断路器回复使用,如果有则打开断路器使请求不可用

在这里插入图片描述

  • 资源名:请求路径
  • 降级策略:
    • RT(ms):平均响应时间,秒级;平均响应时间超出阈值在时间窗口内通过的请求>=5,两个条件同时满足后触发降级;窗口期过后关闭断路器;RT最大可设置为4900ms(更大的需要通过设置-Dcsp.sentinel.statistic.max.rt=xxxx才能生效)
    • 异常比例(0.0 ~ 1.0):QPS >= 5异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后关闭降级)
    • 异常数:异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后关闭降级;如果选择了异常数,那么时间窗口必需大于60,因为异常数是以分钟为单位进行统计的,如果小于60,则结束熔断后可能会导致再次进入熔断状态
  • 时间窗口:降级时间间隔(秒),在时间窗口时间内,对该资源的调动都会自动熔断。
4.3、热点规则

(1)如果该请求携带了指定索引位置的参数,并达到了阈值,则触发降级;
(2)如果该请求没有携带指定索引位置的参数,则不会触发降级;
(3)如果设置了参数例外项,且请求携带的参数是指定索引位置的参数,如果参数值和设置的一致,那么阈值将会调整为参数例外项中设置的阈值;

在这里插入图片描述

  • 资源名:请求路径
  • 限流模式:固定为QPS
  • 参数索引:请求接口的参数索引,从0开始
  • 单机阈值:接口每秒内的请求次数阈值,达到设定的值后降级
  • 统计窗口时长:
  • 参数例外项:
    • 参数类型:int、double、long、float、char、byte、java.lang.String
    • 参数值:指定索引参数的参数值
    • 限流阈值:新的阈值
4.4、系统规则

系统自适应限流,从整体维度对一个用入口进行限流

  • 除了CPU使用率的阈值为[0,1]的小数外,其余的都是[0, ~) 的正整数
    在这里插入图片描述
  • LOAD(自适应,仅对Linux/Unix-like机器生效):系统的load1作为启发指标,进行自适应系统保护。当系统load1超过设定的其法制,且系统当前的并发线程超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的 maxQps * minRt估算得出。设定的参考值一般是 CPU cores * 2.5;
  • 平均RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是ms
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护
  • 入口QPS:当单台机器上所有入口流量的QPS达到阈值即触发系统保护
  • CPU使用率(1.5.0+的版本):当系统的CPU使用率超过阈值即触发系统保护[0.0, 1.0]
4.5、@SentinelResource注解

用于配置降级等功能
注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理

  • 常用属性
    • value:必填;属性值可作为资源名(尽量不要和接口注解名称一致)
    • blockHandlerClass:指定降级方法所在类
    • blockHandler:指定降级方法,必需是public方法,返回类型、参数类型和原方法一致,在最后需要添加一个额外的参数(BlockException);默认和原方法在同一个类,不在则需要指定blockHandlerClass,且该方法必须为static方法
    • fallbackClass:指定fallback方法所在类
    • fallback:指定fallback方法,用于在抛出异常后提供fallback逻辑处理,可以针对除exceptionToIgnore 里面排除的所有类型的异常;返回类型、参数列表和原方法一致,也可以加一个Throwable类型参数,用于接收对应的异常;默认和原方法在用一个类中,不在则需要用fallbackClass指定方法所在类,且方法必需是static方法
    • defaultFallback (since 1.6.0):默认的fallback方法名,用于通用的fallback;作用与fallback类似,不同的是指定的方法参数列表需要为空,或者可以加一个Throwablw类型参数;当fallback和defaultFallBack同时配置,只有fallback会生效
    • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
    • 特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出。

十二、Spring Cloud Alibaba — Seata

分布式事务解决方案

1、相关概念

在这里插入图片描述

  • Transaction ID XID:全局唯一的事务ID
  • 三组件:
    • TC - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚
    • TM - 事务管理器:定义全局事务的范围:开始全局事务、提交、回滚全局事务
    • RM - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
  • 流程:
    • TM 向 TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID
    • XID 在微服务调用链上下文中传播
    • RM 向 TC 注册分支事务,将其纳入 XID 对应的全局事务的管辖
    • TM 向 TC 发起针对XID的全局提交或混滚决议
    • TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求

2、安装

2.1、修改配置文件

conf/file.conf,修改两处

(1)找到service节点,可修改如图红框中的值
在这里插入图片描述
(2)找到store 节点
修改mode为db,随后找到db节点,填写自己的数据库配置信息
在这里插入图片描述
在这里插入图片描述

conf/registry.conf,修改一处

找到registry节点,根据实际需求选择注册中心
在这里插入图片描述

2.2、创建seata需要的数据库

新建数据库:seata,执行conf/db_store.sql 的脚本创建相关数据表

3、运行

进入bin目录,运行seata-server.bat

4、微服务集成seata

  • Spring Cloud Alibaba的依赖‘
<dependencyManagement>
	 <dependencies>
	     <dependency>
	         <groupId>com.alibaba.cloud</groupId>
	         <artifactId>spring-cloud-alibaba-dependencies</artifactId>
	         <version>2.1.0.RELEASE</version>
	         <type>pom</type>
	         <scope>import</scope>
	     </dependency>
	 </dependencies>
</dependencyManagement>
  • 需要的依赖
<!--nacos-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- seata -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>seata-all</artifactId>
            <groupId>io.seata</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    <version>0.9.0</version>
</dependency>
  • yml配置文件
server:
  port: 2002

spring:
  application:
    name: cloud-alibaba-seata-storage
  cloud:
    alibaba:
      seata:
        # 自定义事务组名称需要与seata-server中的对应,我们之前在seata的配置文件中配置的名字
        tx-service-group: xzk_tx_group
    nacos:
      discovery:
        server-addr: localhost:8848
  • 微服务除了自己的业务表外,还需要一张seata的回滚日志表,执行 conf/db_undo_log.sql
-- the table to store seata xid data
-- 0.7.0+ add context
-- you must to init this sql for you business databese. the seata server not need it.
-- 此脚本必须初始化在你当前的业务数据库中,用于AT 模式XID记录。与server端无关(注:业务数据库)
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
drop table if exists `undo_log`;
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  • 将2.1 中修改过的配置文件放到微服务项目中
  • 分布式事务如何生效
    • 需要在事务发起方添加注解@GlobalTransactional(name = "global-transaction-name")
    • 在分布式事务中,事务参与方不要使用try{} catch(){} 去捕获异常信息,可以在事务的发起方使用try{} catch(){} 进行捕获,如果在非事务发起方进行捕获,那么事务发起方将无法正确捕获异常和进行事务回滚;

5、seata原理

在这里插入图片描述

  • TM 开启分布式事务(TM 向 TC注册全局事务记录)
  • 按业务场景,编排数据库、服务等事务资源(RM 向 TC汇报资源准备状态)
  • TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务)
  • TC 汇总事务信息,决定分布式事务是提交还是回滚
  • TC通知所有 RM 提交/回滚资源,事务二阶段结束
5.1、第一阶段

在一阶段,Seata会拦截 业务SQL
在这里插入图片描述

  • 以下操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性
    • 解析SQL语义,找到业务SQL要更新的业务数据,在业务数据被更新前,将其保存成before image
    • 执行业务SQL更新业务数据
    • 业务数据更新后,将更新后的数据保存为after image
    • 生成行锁
5.2、第二阶段

(1)提交

如果是顺利提交,因为业务SQL在第一阶段已经提交至数据库中,所以seata框架只需将第一阶段保存的快照数据和行锁删掉,完成数据清理即可

在这里插入图片描述
(2)回滚

如果是回滚,Seata就需要回滚第一阶段已经执行的业务SQL,并还原业务数据,回滚方式便是用before image还原业务数据;但在还原前首先校验脏写,对比数据库当前业务数据after image,如果两份数据完全一致就说明没有脏写,可以还原业务数据,反之就说明有脏写,需要人工处理

此处的脏写:在回滚之前,其他请求已经成功修改过这条数据,那么当前就不能回滚了

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值