【Spring】SpringCloudAlibaba学习笔记

news2024/10/7 22:52:19

Nacos

  1. Nacos是一个更易于构建云原生应用的动态服务发现/服务配置服务管理平台
  2. 核心功能:
    1. 服务注册: Nacos Client会通过发送REST请求向Nacos Server注册自己的服务, 提供自己的元数据, 如ip地址/端口等信息; Nacos Server收到注册请求后, 就会把这些信息存储在Map中
    2. 服务心跳: 在服务注册后, Nacos Client会维护一个定时心跳来持续通知Nacos Server, 说明服务一致处于可用状态, 防止被剔除 默认5s发送一次心跳
    3. 服务发现: 服务消费者在调用服务提供者的服务时, 会发送一个REST请求给Nacos Server, 获取上面注册的服务清单, 并且缓存在Nacos Client本地; 同时在Nacos Client本地开启一个定时任务定时拉取最新的注册表信息到本地缓存
    4. 服务健康检查: Nacos Server会开启一个定时任务来检查注册服务实例的健康情况, 对于超过15s没有收到客户端心跳的实例会将它的healthy属性置为false; 如果某个实例超过30s没有收到心跳, 直接剔除该实例

主流注册中心对比

指标NacosEurekaConsulCoreDNSZookeeper
一致性协议CP/APAPCP-CP
健康检查TCP/HTTP/MySQL/Client BeatClient BeatTCP/HTTP/gRPC/Cmd--
负载均衡策略权重/metadata/SelectorRibbonFabioRoundRobin-
雪崩保护
自动注销实例支持支持支持不支持支持
访问协议HTTP/DNSHTTPHTTP/DNSDNSTCP
监听支持支持支持支持不支持支持
多数据中心支持支持支持不支持不支持
跨注册中心同步支持不支持支持不支持不支持
SpringCloud集成支持不支持支持不支持支持
Dubbo集成支持不支持支持不支持支持
K8S集成支持不支持支持支持不支持

基本使用

集群部署1

apiVersion: v1
kind: Service
metadata:
  name: nacos-svc
spec:
  type: LoadBalancer
  ports:
    - port: 8848
      name: server
      targetPort: 8848
    - port: 9848
      name: client-rpc
      targetPort: 9848
    - port: 9849
      name: raft-rpc
      targetPort: 9849
    ## 兼容1.4.x版本的选举端口
    - port: 7848
      name: old-raft-rpc
      targetPort: 7848
  selector:
    app: nacos
---
apiVersion: v1
kind: Service
metadata:
  name: nacos-headless
  labels:
    app: nacos-headless
spec:
  type: ClusterIP
  clusterIP: None
  ports:
    - port: 8848
      name: server
      targetPort: 8848
    - port: 9848
      name: client-rpc
      targetPort: 9848
    - port: 9849
      name: raft-rpc
      targetPort: 9849
    ## 兼容1.4.x版本的选举端口
    - port: 7848
      name: old-raft-rpc
      targetPort: 7848
  selector:
    app: nacos
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nacos-cm
data:
  mysql.host: "server.passnight.local"
  mysql.db.name: "nacos_devtest"
  mysql.port: "3306"
  mysql.user: "nacos"
  mysql.password: "*****************"
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nacos
spec:
  serviceName: nacos-headless
  replicas: 3
  template:
    metadata:
      labels:
        app: nacos
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
    spec:
      containers:
        - name: nacos
          imagePullPolicy: Always
          image: nacos/nacos-server:latest
          resources:
            requests:
              memory: "128Mi"
              cpu: "500m"
          ports:
            - containerPort: 8848
              name: client
            - containerPort: 9848
              name: client-rpc
            - containerPort: 9849
              name: raft-rpc
            - containerPort: 7848
              name: old-raft-rpc
          env:
            - name: NACOS_REPLICAS
              value: "3"
            - name: MYSQL_SERVICE_HOST
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.host
            - name: MYSQL_SERVICE_DB_NAME
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.db.name
            - name: MYSQL_SERVICE_PORT
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.port
            - name: MYSQL_SERVICE_USER
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.user
            - name: MYSQL_SERVICE_PASSWORD
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.password
            - name: SPRING_DATASOURCE_PLATFORM
              value: "mysql"
            - name: MYSQL_SERVICE_DB_PARAM
              value: characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
            - name: NACOS_SERVER_PORT
              value: "8848"
            - name: NACOS_APPLICATION_PORT
              value: "8848"
            - name: PREFER_HOST_MODE
              value: "hostname"
            - name: NACOS_SERVERS
              value: "nacos-0.nacos-headless.default.svc.cluster.local:8848 nacos-1.nacos-headless.default.svc.cluster.local:8848 nacos-2.nacos-headless.default.svc.cluster.local:8848"
  selector:
    matchLabels:
      app: nacos

注意这里会报错

error: error validating "nacos.yml": error validating data: ValidationError(StatefulSet.spec.template.metadata): unknown field "spec" in io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta; if you choose to ignore these errors, turn validation off with --validate=false

需要添加一层spec标签2

再登录会报错No DataSource set

需要配置MySQL8的一些常用配置项3并自己执行初始化脚本4; 需要执行对应版本的sql脚本nacos/distribution/conf/nacos-mysql.sql at 2.0.3 · alibaba/nacos (github.com) docker:latest对应的是2.0.3

这里把节点亲和性给去掉了; 允许所有节点部署Nacos

然后使用用户名nacos密码nacos就可以登陆了

在这里插入图片描述

java应用代码

使用nacos首先要引入Maven依赖

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.9.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

然后再application.properties添加必要的配置

# 这个对应服务名
spring.application.name=stock-service 
spring.cloud.nacos.server-addr=192.168.100.73:8848
# 后面三项式默认配置
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
spring.cloud.nacos.discovery.namespace=public

之后就可以在服务列表中看到相应的服务了

在这里插入图片描述

Nacos服务发现

在服务注册后, 就可以通过服务名进行调用和负载均衡了

首选准备带负载均衡功能的客户端:

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

然后准备两个服务

@AllArgsConstructor
@RestController
@RequestMapping("/OrderController")
public class OrderController {

    private final RestTemplate restTemplate;


    @GetMapping("/add")
    public String add() {
        String response = restTemplate.getForObject("http://stock-service/StockService/reduce", String.class);
        return "In order-service, stock-service response: " + response;
    }
}

@RestController
@RequestMapping("/StockService")
public class StockController {
    @GetMapping("/reduce")
    public String reduce() {
        return "reduce stock";
    }
}

之后调用订单服务, 订单服务就会调用到库存服务 默认的负载均衡器是robbin

passnight@passnight-s600:~$ curl localhost:8010/OrderController/add
In order-service, stock-service response: reduce stock

配置中心使用

  1. Nacos提供用于配置存储和其他元数据的key/value存储; 为分布式系统中的外部化配置提供服务器端和客户端支持. 使用Spring Cloud Alibaba Nacos Config, 可以在Nacos Server中集中管理配置
  2. 使用Nacos有以下好处
    1. 易维护
    2. 时效性
    3. 安全性

Dubbo

  1. Dubbo以一款高性能的RPC框架
    1. 面向接口代理的高性能RPC调用: 为开发者屏蔽调用的底层细节
    2. 智能负载均衡
    3. 服务自动注册与发现
    4. 高扩展: 基于微内核+插件设计; 几乎所有的核心能力都支持第三方实现
    5. 运行期流量调度: 通过配置路由规则, 可以实现灰度发布/同机房优先等功能
    6. 可视化的服务治理与运维: 提供可视化的运维工具和服务治理工具

使用

安装dubbo-admin

version: "3.0"
services:
  dubbo-admin:
    image: apache/dubbo-admin:0.6.0
    container_name: dubbo-admin
    ports:
      - "20018:38080"
    volumes:
      - /opt/docker/dubbo-admin/data:/data
    environment:
      admin.registry.address: nacos://192.168.100.71:8848
      admin.config-center: nacos://192.168.100.71:8848
      admin.metadata-report.address: nacos://192.168.100.71:8848
    restart: always

然后使用docker-compose up -d启动即可

暴露服务

  1. 引入dubbo依赖

            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-spring-boot-starter</artifactId>
                <version>2.7.23</version>
            </dependency>
            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>okhttp</artifactId>
                <version>4.10.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-registry-nacos</artifactId>
                <version>2.7.23</version>
            </dependency>
    

原理

负载均衡机制

  1. RandomLoadBalance: 基于权重的随机负载均衡
  2. RoundRobinLoadBalance: 基于权重的轮询负载均衡 差分轮询算法
  3. LeastActiveLoadBalance: 最少活跃数负载均衡机制, 总是选择响应速度最快的服务
  4. ConsistentHashLoadBalance: 基于一致性哈希算法的负载均衡机制

Sentinel

基本概念

  1. 在微服务调用链路中某个服务故障, 引起整个链路中的微服务都不可用, 即雪崩

  2. 解决雪崩的方法

    1. 超时处理: 设定超时时间, 请求超过一定时间没有响应就返回错误信息, 不会无休止等待
    2. 仓壁模式: 限制每个业务所能够使用的资源, 以避免部分业务耗尽整个系统的资源; 即线程隔离
    3. 熔断降级: 由断路器统计业务执行的异常比例, 如果超出阈值则熔断该业务, 拦截访问该业务的一切请求
    4. 流量控制: 限制业务访问的QPS; 避免服务因为流量突增而故障
  3. 实现服务保护的技术对比:

    技术SentinelHystrix
    隔离策略信号量线程池/信号量
    熔断降级策略基于慢调用比例或异常比例基于失败比例
    实时指标实现滑动窗口滑动窗口(基于RxJava)
    规则配置支持多种数据源支持多种数据源
    扩展性多个扩展点插件形式
    基于注解的支持支持支持
    线瘤基于QPS, 支持基于调用关系的限流有限的支持
    流量整形支持慢启动/匀速排队模式不支持
    系统自适应保护支持不支持
    控制台开箱即用, 可配置规则, 查看秒级监控, 机器发现等不完善
    常见的框架的适配Servlet/Spring Cloud/ Dubbo/ gRPC等Servlet/ Spring Cloud Netfix

基本使用

  1. 安装dashboard

    version: "2.1"
    services:
      sentinel-dashboard:
        image: bladex/sentinel-dashboard:1.8.0
        container_name: sentinel-dashboard
        ports:
          - "20019:8858"
    
  2. 引入依赖

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>
    
  3. 配置dashboard地址

    spring.cloud.sentinel.transport.dashboard=server.passnight.local:20019
    
  4. 之后就可以在dashboard中看到请求信息了

    在这里插入图片描述

  5. 选中端点并配置流量限制; 然后就可以实现流控了:

    1. 在这里插入图片描述

    2. 在这里插入图片描述

限流规则

  1. 簇点链路: 即项目中的调用链路, sentinel默认监控SpringMVC中的端点
  2. 流控模式:
    1. 关联: 统计与当前资源相关的另一个资源, 触发阈值时, 触发当前资源的限流 当read QOS达到阈值时, 对write限流

      1. 在这里插入图片描述
    2. 链路模式: 根据请求来源进行限流; 使用@SentinelResource将服务中的方法设置为资源

    3. 热点参数请求: 根据参数进行限流, 需要添加@SentinelResource才能生效 查询下, 对不同资源分别限流

  3. 流控效果:
    1. 快速失败: 达到阈值后, 新的请求会立即被拒绝, 并抛出异常 默认处理方式
    2. 预热模式: 对超出阈值的请求同样抛出异常, 但阈值会动态变化, 从最小值增加到最大值; 初识阈值为 t h r e s h o l d c o l d F a c t o r \frac{threshold}{coldFactor} coldFactorthreshold; 等待预热时间后达到阈值QPS
    3. 排队等待: 将请求放入队列, 直到预期等待时长请求超出等待时长才会拒绝请求 流量整形

隔离和降级

  1. 熔断降级: 断路器统计服务调用的异常比例/慢比例; 若超过阈值就会熔断该服务, 当服务恢复时自动放行该服务的请求 熔断时解决雪崩的重要手段, 即当服务异常则停止其提供服务

    失败达到阈值
    熔断时间结束
    success
    快速失败
    失败打开断路器
    一次请求成功, 关闭断路器
    Closed
    Open
    Half Open
  2. 熔断策略: 熔断策略有三种, 慢调用/异常比例/异常数

    1. 慢调用: 业务的相应时长(RT), 大于指定时长请求认定为慢调用请求, 在指定时间内, 如果请求数量超过最小数量, 慢调用比例大于设定值, 则触发熔断
    2. 异常比例/异常数: 指定事件内的调用, 若调用次数超过指定请求数, 且异常比例/异常数超过阈值, 则触发熔断
  3. 授权规则: 根据调用方来源进行控制, 有白名单黑名单两种方式例如绕过网关则block, 可以通过添加http header实现

  4. 自定义异常: 实现BlockExceptionHandler接口即可

规则持久化

  1. Sentinel控制台的规则管理有三种模式:

    1. 原始模式: 将规则保存在内存当中, 重启服务会丢失 默认模式

    2. pull模式: 控制台将配置的规则推送到Sentinel客户端, 而客户端会将规则持久化, 之后定时去本地文件或数据库中查询, 更新本地规则

      在这里插入图片描述

    3. push模式: 控制台将配置规则推送到配置中心, 服务监听配置中心 需要自己实现

      在这里插入图片描述

实现原理

Hystrix实现原理5

  1. 根据Hystrix的流程图来看, Hystrix主要实现的功能有三点:
    1. 缓存请求: 若请求结果在缓存当中, 则直接返回缓存中的结果
    2. 断路保护: 若命中了断路规则, 则直接断路, 执行fallback函数
    3. 池化请求: 由线程池(信号量)创建并执行请求; 因此若发生异常, 可以将异常隔离在Hystrix的线程池当中
    4. 在这里插入图片描述

Seata

项目准备

CREATE TABLE account_t
(
    id      BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id VARCHAR(64),
    money   DOUBLE
);
CREATE TABLE storage_t
(
    id             BIGINT PRIMARY KEY AUTO_INCREMENT,
    commodity_code VARCHAR(64),
    count          INT
);

CREATE TABLE order_t
(
    id             BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id        VARCHAR(64),
    commodity_code VARCHAR(64),
    count          INT,
    money          DOUBLE
);

INSERT INTO account_t (user_id, money) VALUE ('user1', 1000);
INSERT INTO storage_t(commodity_code, count) VALUE ('00001', 10);

请求

curl -X POST -d '{"userId": "user1", "commodityCode": "00001", "count": 2, "money": 200}' --header "Content-Type: application/json" server.passnight.local:8010/OrderController/create-order

触发库存不足异常:

curl -X POST -d '{"userId": "user1", "commodityCode": "00001", "count": 20, "money": 200}' --header "Content-Type: application/json" server.passnight.local:8010/OrderController/create-order

OrderService因为rpc调用失败, 且标注了@Transactional所以事务回滚; StockService因为异常所以没有扣减库存; 但UserService正常执行, 账户被扣减; 这不符合业务要求.

基本概念

  1. Seata事务管理中有三个重要角色:
    1. 事务协调者(Transaction CVoordinator): 维护全局和分支事务的状态, 协调全局事务提交或回滚
    2. 事务管理器(Transactrion Manager): 定义全局事务的范围, 开始全局事务, 提交或回滚全局事务
    3. 资源管理器(Resource Manager): 管理分支事务处理的资源, 与事务TC交谈以注册分支事务和报告分支事务的状态, 并驱动分支事务提交或回滚
  2. Seata分布式解决方案
    1. XA模式: 强一致分阶段事务模式, 牺牲一定的可用性, 无业务侵入
    2. TCC模式: 最终一致性的分阶段事务模式, 有业务侵入
    3. AT模式: 最终一致性的分阶段事务模式, 无业务侵入 是Seata的默认模式
    4. SAGA模式: 长事务模式, 有业务侵入

基本使用

部署TC服务

version: "3"
services:
  seata-server:
    container_name: seata-server
    image: seataio/seata-server:2.0.0
    hostname: seata-server
    ports:
      - "20020:8091"
      - "20021:7091"
    volumes:
      - "/opt/docker/seata/config:/seata-server/resources"
      - "/etc/localtime:/etc/localtime"
      - "/etc/timezone:/etc/timezone"
    environment:
      - SEATA_PORT=8091
      - STORE_MODE=file

建表

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
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_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
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 = utf8mb4;

-- the table to store lock data
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),
    `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

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

添加

[lock.DataBaseDistributedLocker] [              <init>]  [] : The distribute lock table is not config, please create the target table and config it
store.db.distributed-lock-table=distributed_lock

分布式事务

XA模式

  1. Seata XA模式是在数据库XA模式上做了简单的封装 Seata的RM仅转发事务到db的RM
  2. 特点
    1. 优点:
      1. 强一致性, 满足ACID原子
      2. 常用的数据库都支持, 实现简单, 且没有代码侵入
    2. 缺点
      1. 一阶段需要锁定资源, 等到二阶段结束后才能释放, 性能较差
      2. 依赖关系型数据库实现事务 例如redis不支持XA, 则无法使用XA模式
实现
  1. 引入依赖

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            </dependency>
    
  2. 启动Seata

    @EnableSeataSpringConfig
    
  3. 配置Seata

    # seata
    seata.registry.type=nacos
    seata.registry.nacos.server-addr=192.168.100.71:8848
    seata.registry.nacos.namespace=public
    seata.registry.consul.cluster=default
    seata.config.nacos.group=SEATA_GROUP
    seata.registry.nacos.application=seata-server
    seata.tx-service-group=seata-sell
    # use XA mode
    seata.data-source-proxy-mode=XA
    seata.service.vgroup-mapping.seata-sell=default
    
  4. 在方法上标注@GlobalTransactional

        @Override
        @GlobalTransactional
        public Long createOrder(Order order) {
            orderMapper.insert(order);
            accountService.deduct(order.getUserId(), order.getMoney());
            stockService.deduct(order.getCommodityCode(), order.getCount());
            return order.getId();
        }
    

AT模式

  1. AT模式同样是分阶段提交的事务模型, 不过弥补了XA模型中锁定周期过长的缺陷 相比于XA模式, 它会直接提交事务; 而非等待执行

  2. 回滚方式: RM会拦截事务, 并生成undo快照, 失败则执行undo操作

  3. 二阶段提交只需要删除undo log; 并且报告TC的操作可以异步, 因为资源已经释放

  4. 在这里插入图片描述

  5. 可能存在的问题:

    事务1和事务2同时执行update account set money = money - 10 where id = 1

    事务1事务2
    获取锁, 保存快照{id: 1, money: 100}
    执行sql, set money = 90
    提交事务, 释放DB锁
    获取DB锁, 保存快照: {id : 1, money: 90}
    执行sql, set money = 80
    提交事务 释放DB锁
    回滚, set money = 100

    该过程丢失了事务2的更新

  6. 为了解决该问题, 使用全局锁实现写隔离, 全局锁有类似以下结构:

    xid(事务id)table(表)pk(行号)

    使用该数据结构隔离其他事务更新; 这样执行流程就变成了:

    事务1事务2
    获取锁, 保存快照{id: 1, money: 100}
    执行sql, set money = 90
    提交事务, 释放DB锁
    获取DB锁, 保存快照: {id : 1, money: 90}
    执行sql, set money = 80; 但需要等待全局锁
    回滚, set money = 100, 但需要等待DB锁 此时产生了死锁
    任务超时, 回滚业务, 释放全局锁
    获取DB锁, 根据快照恢复数据
  7. 尽管加了全局锁, 但该全局锁由Seata管理, 因此非Seata管理的服务可以访问该数据; 且锁的粒度是;

  8. 对于非Seata管理的全局事务, AT模式模式通过以下方式管理

    事务1事务2
    获取锁, 保存快照before-image: {id: 1, money: 100}
    执行sql, set money = 90
    提交事务, 释放DB锁
    获取DB锁
    保存快照after-image: {id: 1, money: 90}
    执行sql, set money = 80; 无需等待全局锁
    提交事务, 释放DB锁
    回滚, 将当前数据与after-image对比, 发现 90 ≠ 80 90 \ne 80 90=80; 说明数据被其他事务修改
    此时记录异常, 发送警告, 人工介入
  9. 特点

    1. 优点:

      1. 一阶段提交事务, 直接释放数据库资源, 性能较好
      2. 利用全局锁实现读写隔离
      3. 没有代码侵入, 框架自动完成代码的回滚和提交
    2. 缺点

      1. 两个阶段之间属于软状态, 属于最终一致性方案
      2. 框架的快照功能会影响性能, 但依旧比XA模式好很多
实现
  1. 在微服务中创建undo_log的表

    CREATE TABLE undo_log
    (
        branch_id     BIGINT(20)   NOT NULL COMMENT 'branch transaction id',
        xid           VARCHAR(100) 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 'creation time',
        log_modified  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
        UNIQUE INDEX uni_undo_log (xid, branch_id)
    )
    
  2. 开启seataAT模式: seata.data-srouce-proxy-mode=AT

TCC模式

  1. TCC模式与AT模式相似, 每个阶段都是独立事务; 区别在于TCC是通过人工编码实现数据恢复的:

    1. Try: 资源的检测和预留
    2. Confirm: 完成资源操作业务
    3. Cancel: 预留资源释放 可以理解为Try的反向操作
  2. 在这里插入图片描述

  3. 举例(扣减用户余额30元):

    1. Try: 冻结金额30元
    2. Confirm: 清除掉冻结金额
    3. Cancel: 余额增增加冻结金额的值
  4. 特点

    1. 优点
      1. 性能好
      2. 不依数据库事务, 因此可以支持非事务型数据库
    2. 缺点
      1. 代码侵入性较大
      2. 软状态, 是最终一致性模型
      3. 需要考虑Confirm和Cancel的失败情况, 做好幂等处理
  5. 空回滚: 某分支try阶段阻塞, 导致全局事务触发cancel操作; 没有try的操作也要执行cancel操作, 此时cancel不能修改数据, 这就是空回滚: 在这里插入图片描述

  6. 业务悬挂: 在执行空回滚之后, try恢复, 此时不能执行try操作, 这就是业务悬挂

使用TCC实现扣款功能
  1. 需求:

    1. 编写TCC业务逻辑
    2. Try: 冻结金额, 扣减可用金额
    3. configm: 删除冻结金额
    4. cancel: 删除冻结金额, 恢复可用金额
    5. 保证confirm和cancel接口的幂等性 因为这些接口可能会因为执行失败重试
    6. 允许空回滚
    7. 拒绝业务悬挂
  2. 创建冻结表

    CREATE TABLE account_freeze_t
    (
        xid          VARCHAR(128) PRIMARY KEY NOT NULL,
        user_id      VARCHAR(255)    DEFAULT NULL COMMENT '用户id',
        freeze_money DOUBLE UNSIGNED DEFAULT 0 COMMENT '冻结金额',
        state        INT(1)          DEFAULT NULL COMMENT '事务状态, 0:try, 1:confirm, 2:cancel'
    );
    

SAGA模式

  1. SAGA模式是seata提供的长事务解决方案; 也分为两个阶段

    1. 阶段1: 直接提交本地事务 与TCC不同的是, tcc是在confirm阶段提交事务
    2. 阶段2: 若成功则什么都不做, 若失败则通过编写补偿业务回滚
  2. 在这里插入图片描述

  3. 特点:

    1. 优点:
      1. 基于事件驱动实现异步调用, 吞吐量高
      2. 一阶段直接提交, 性能较好
      3. 不用编写TCC三个阶段, 实现简单
    2. 缺点:
      1. 软状态持续时间不确定, 时效性差
      2. 没有锁, 没有事务隔离, 因此有脏写问题

引用


  1. Kubernetes Nacos ↩︎

  2. [google cloud platform - Kubernetes: Error validating data: ValidationError(Deployment.spec): unknown field “containers” in io.k8s.api.apps.v1.DeploymentSpec - Stack Overflow ↩︎

  3. https://github.com/nacos-group/nacos-docker/issues/251#issuecomment-1102186326 ↩︎

  4. https://github.com/nacos-group/nacos-docker/issues/251#issuecomment-1613891832 ↩︎

  5. How it Works · Netflix/Hystrix Wiki (github.com) ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1870640.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

远程工具的使用

远程连接工具的作用&#xff0c;通过远程连接到服务器上&#xff0c;方便操作&#xff01; 1.常见的远程连接工具 XShell&#xff1a;这是一款Windows平台下的SSH客户端软件&#xff0c;支持SSH1、SSH2、SFTP、TELNET、RLOGIN等多种协议&#xff0c;功能丰富&#xff0c;包…

计算机二级Access操作题总结——综合应用

属性表相关 例1&#xff1a; 不允许输入和修改其中的数据→【是否锁定】 例2&#xff1a; 单击“退出”按钮(名为“bt2”)&#xff0c;调用设计好的宏“mEmp”来关闭窗体。 分组和汇总 对“rSell”报表进行适当设置&#xff0c;使每名雇员的姓名显示在该雇员所售书籍信…

Python学习笔记24:进阶篇(十三)常见标准库使用之数据压缩功能模块zlib,gzip,bz2,lzma的学习使用

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 数据压缩…

C语言的内存知识

这节我们主要认识一下内存&#xff0c;便于理解指针操作和后续内存管理。 一、内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 &#xff08;可以结合函数小节的函数栈帧部分看一下&#xff09; ⚪ 代码区:存放函数体的二进制代码&#xff0c;由操作系统进…

wgcloud怎么保证数据的安全性

WGCLOUD做了以下方面来保证数据安全 1、私有化部署 WGCLOUD是完全本地部署&#xff0c;没有云端服务&#xff0c;因此不用担心数据被他人获取 2、加密传输数据 WGCLOUD支持https传输数据&#xff0c;查看配置说明&#xff0c;实现使用SSL证书https访问server页面 - WGCLOUD…

第一后裔/The First Descendant延迟高的解决方法

第一后裔/The First Descendant是一款备受玩家关注的射击游戏&#xff0c;该作拥有多个角色&#xff0c;并为其设定不同的概念和战斗风格&#xff0c;以及技能点&#xff0c;不仅能让玩家畅快作战&#xff0c;还能通过各种道具&#xff0c;不断强化角色能力值&#xff0c;让其战…

Python 基础:使用 unittest 模块进行代码测试

目录 一、测试函数2.1 通过案例2.2 不通过案例2.3 添加新测试 二、测试类2.1 单个测试案例2.2 多个测试案例 三、总结 遇到看不明白的地方&#xff0c;欢迎在评论中留言呐&#xff0c;一起讨论&#xff0c;一起进步&#xff01; 本文参考&#xff1a;《Python编程&#xff1a;…

Jenkins教程-9-发送企业微信测试报告通知

上一小节我们学习了Jenkins上下游关联自动化测试任务的构建的方法&#xff0c;本小节我们讲解一下发送企业微信测试报告通知的方法。 1、自动化用例执行完后&#xff0c;使用pytest_terminal_summary钩子函数收集测试结果&#xff0c;存入本地status.txt文件中&#xff0c;供J…

Arathi Basin (AB) PVP15

Arathi Basin &#xff08;AB&#xff09; PVP15 阿拉希盆地&#xff0c;PVP&#xff0c;15人战场

【银河麒麟】高可用触发服务器异常重启,处理机制详解

1.服务器环境以及配置 【机型】物理机 处理器&#xff1a; Intel 内存&#xff1a; 126G 【内核版本】 4.19.90-25.16.v2101.ky10.x86_64 【银河麒麟操作系统镜像版本】 Kylin-Server-10-SP2-Release-Shenzhen-Metro-x86-Build01-20220619 Kylin-HA-10-SP2-Release-S…

前端vue3 根据某些Id 筛选数据

现在有一些不等的数据 我需要通过前端 吧这个数据筛选一下 比如我使用一些 我需要的ID 下的数据 比如以上的数据 的 cinemaLineId 来筛选 const cinemaLineId ref(["1246429254713147392", "1182608813770321920", "1182608917403185152"])…

大数据之Hadoop部署

文章目录 服务器规划服务器环境准备1. 网络测试2. 安装额外软件包3. 安装基础工具4. 关闭防火墙5. 创建用户并配置权限6. 创建目录并设置权限7. 卸载JDK8. 修改主机名9. 配置hosts文件10. 重启服务器 配置免密登录安装Java安装Hadoop1. Hadoop部署2. 配置Hadoop3. 格式化Hadoop…

【PyQt5】一文向您详细介绍 QVBoxLayout() 的作用

【PyQt5】一文向您详细介绍 QVBoxLayout() 的作用 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&a…

机器人控制系列教程之URDF文件语法介绍

前两期推文&#xff1a;机器人控制系列教程之动力学建模(1)、机器人控制系列教程之动力学建模(2)&#xff0c;我们主要从数学的角度介绍了机器人的动力学建模的方式&#xff0c;随着机器人技术的不断发展&#xff0c;机器人建模成为了机器人系统设计中的一项关键任务。URDF&…

我只有一点Python基础,对学习WebGIS开发有帮助吗?

经常有人后台私信问&#xff0c;我只有一点Python基础&#xff0c;对学习GIS开发有帮助吗&#xff1f; 关于这个问题的答案是&#xff0c;当然有&#xff01;Python适用于WebGIS开发。WebGIS是地理信息系统&#xff08;GIS&#xff09;技术与Web技术的结合&#xff0c;而Pytho…

Go语言学习:每日一练2

Go语言学习&#xff1a;每日一练2 目录 Go语言学习&#xff1a;每日一练2结构体零值数组切片映射指针 各个类型的零值一览 结构体 //定义 type Vertex struct {X, Y int } //使用 func main() { v1 : Vertex{1, 2} fmt.Println(v.X) //别的实例化方式 var v2 Vertex v2 : *new…

《PIDNet: A Real-time Semantic Segmentation Network Inspired by PID Controllers》

期刊&#xff1a;CVPR 年份&#xff1a;2023 代码&#xff1a;https://github.com/XuJiacong/PIDNet 摘要 双分支网络架构已经证明了它在实时语义分割任务中的有效性和有效性。然而&#xff0c;高分辨率细节和低频上下文的直接融合的缺点是细节特征很容易被周围的上下文信息…

Nuxt3 的生命周期和钩子函数(三)

title: Nuxt3 的生命周期和钩子函数&#xff08;三&#xff09; date: 2024/6/27 updated: 2024/6/27 author: cmdragon excerpt: 摘要&#xff1a;概述了Nuxt3的关键生命周期钩子用途&#xff0c;如page:finish用于页面加载后处理&#xff0c;page:transition:finish处理过…

MySQL数据库简介和安装

文章目录 一、数据库原理目前情况数据库的发展史RDBMS关系型数据库关系型数据库理论 二、MySQL历史发展历程关系型数据库和非关系型数据库 三、安装mysql及优化yum安装编译安装mysql二进制安装优化操作 四、 安装mycli插件客户端工具 一、数据库原理 目前情况 我们正处于一个…

十三、Maven(1)

&#x1f33b;&#x1f33b;目录 一、maven价绍二、maven的功能1、项目自动化构建2、管理jar、war包3、实现项目结构设计 三、maven安装1、maven的安装环境需要jdk2、Maven的安装路径中不能出现中文和空格3、压缩包解压即可4、配置环境变量 四、maven的仓库1. Maven仓库配置2. …