【Spring】SpringCloudAlibaba学习笔记

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) ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端基础--Vue2

前端技术发展史(了解) 1.前端历史 1.1.静态网页 1990 html 1.2.异步刷新-操作dom 1995 javascript 1.3.动态网站 Asp/jsp&#xff08;java&#xff09;,php等&#xff0c;后台臃肿 1.4.Ajax成为主流 异步请求 1.5.Html5 被认为是互联网的核心技术之一。HTML产生于19…

12,SPI

Flash芯片&#xff1a;W25Q64&#xff0c;可以看成一个储存器 W25Q64芯片和单片机之间的通信方式是SPI SPI:串行同步全双工&#xff0c;主从通信 判断一个设备是不是SPI通信&#xff0c;看是否有这几个线&#xff1a;SCK&#xff0c;CS&#xff0c;MISO&#xff0c;MOSI SCK…

探索Android架构设计

Android 应用架构设计探索&#xff1a;MVC、MVP、MVVM和组件化 MVC、MVP和MVVM是常见的三种架构设计模式&#xff0c;当前MVP和MVVM的使用相对比较广泛&#xff0c;当然MVC也并没有过时之说。而所谓的组件化就是指将应用根据业务需求划分成各个模块来进行开发&#xff0c;每个…

Three.js鼠标拖动设置骨骼姿态

实现 根据SkinnedMesh生成Mesh 作为射线检测的目标&#xff08;射线检测SkinnedMesh存在不足 无法应用骨骼形变的顶点 &#xff09;点击模型 获取点击位置对应的骨骼拖拽鼠标设置骨骼旋转角度&#xff08;使用TransformControl选中点击的骨骼 设置轴为XYZE 并隐藏控件 主动触发…

马面裙的故事:汉服如何通过直播电商实现产业跃迁

【潮汐商业评论/原创】 波澜壮阔的千里江山在马面裙的百褶上展开&#xff0c;织金花纹在女性的步伐之间若隐若现&#xff0c;从明清到现代&#xff0c;如今马面裙又流行了回来&#xff0c;成为女性的流行单品&#xff0c;2024年春节期间&#xff0c;马面裙更是成为华夏女孩们的…

仓库管理系统14--仓库设置

1、添加窗体 <UserControl x:Class"West.StoreMgr.View.StoreView"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc"http://schemas.openxmlformats.…

Str.format()方法

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 在Python2.6之后&#xff0c;提供了字符串的format()方法对字符串进行格式化操作。format()功能非常强大&#xff0c;格式也比较复杂&…

选择第三方软件测试机构做验收测试的好处简析

企事业单位在自行开发完软件系统或委托软件开发公司生产软件之后&#xff0c;有一个必经流程就是验收测试&#xff0c;以验证该产品是否符合用户需求、是否可以上线。为了客观评估所委托生产的软件质量&#xff0c;第三方软件测试机构往往成为企事业单位做验收测试的首选&#…

Bad owner or permissions on C:\\Users\\username/.ssh/config > 过程试图写入的管道不存在。

使用windows连接远程服务器出现Bad owner or permissions 错误 问题&#xff1a; 需要修复文件权限 SSH 配置文件应具有受限权限以防止未经授权的访问 确保只有用户对该.ssh/config文件具有读取权限 解决方案&#xff1a; 在windows下打开命令行&#xff0c;通过以下命令打开文…

PS使用批量脚本生成海报实践

前言 设计朋友有需求做一批邀请函&#xff0c;有几十个人名&#xff0c;需要把人名加到海报中&#xff0c;PS里一个一个添加人名很麻烦&#xff0c;于是来问我有没有什么办法能够批量去添加。 希望把人名加到红框区域内 尝试用ps的脚本进行处理 准备 PS(版本2021&#xff0c;…

HTML静态网页成品作业(HTML+CSS)——企业摄影网介绍网页(3个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有3个页面。 二、作品演示 三、代…

Micro-ROS是什么?

Micro-ROS是ROS&#xff08;Robot Operating System&#xff0c;机器人操作系统&#xff09;生态系统的一个重要组成部分&#xff0c;专为微控制器&#xff08;Microcontrollers&#xff09;设计的轻量级ROS版本。它的目标是在资源有限的嵌入式平台上实现ROS 2的功能&#xff0…

各省药品集中采购平台-地方药品集采分析数据库

国家第十批药品集中采购的启动时间暂未明确&#xff0c;但即将到来&#xff0c;在5月&#xff0c;国家医保局发布了《关于加强区域协同做好2024年医药集中采购提质扩面的通知》&#xff0c;其中明确指出将“开展新批次国家组织药品和医用耗材集中带量采购&#xff0c;对协议期满…

转转游戏MQ重构:思考与心得之旅

文章目录 1 背景1.1 起始之由1.2 重构前现状1.3 问题分析 2 重构2.1 目标2.2 制定方案2.2.1 架构设计2.2.2 实施计划2.2.3 测试计划 2.3 部分细节设计 3. 总结 1 背景 游戏业务自 2017 年启航&#xff0c;至今已近乎走过七个春秋&#xff0c;历经漫长岁月的发展&#xff0c;不…

应用图扑 HT for Web 搭建拓扑关系图

拓扑结构在计算机网络设计和通信领域中非常重要&#xff0c;因为它描述了网络中的设备&#xff08;即“点”&#xff09;如何相互连接&#xff08;即通过“线”&#xff09;。这种结构不仅涉及物理布局&#xff0c;即物理拓扑&#xff0c;还可以涉及逻辑或虚拟的连接方式&#…

C++ ─── vector模拟实现的扩容拷贝问题

扩容拷贝问题 源代码使用memcpy拷贝&#xff0c;在使用vector<int>存储内置类型时没有问题&#xff0c; 但是如果存储的是含有指针的类型&#xff0c;如string&#xff0c;就会发生浅拷贝问题 //3、容量相关void reserve(size_t n){if (n > capacity()){size_t old_si…

数字水产养殖中的鱼类追踪、计数和行为分析技术

随着全球人口增长和生态环境退化&#xff0c;传统捕捞已无法满足人类对水产品的需求&#xff0c;水产养殖成为主要的鱼类来源。数字水产养殖利用先进技术和数据驱动方法&#xff0c;对提高生产效率、改善鱼类福利和资源管理具有显著优势。 1 数字水产养殖的重要性 1.1 提高生…

Java web应用性能分析之【prometheus监控指标体系】

Java web应用性能分析之【系统监控工具prometheus】_javaweb服务器性能监控工具-CSDN博客 Java web应用性能分析之【prometheusGrafana监控springboot服务和服务器监控】_grafana 导入 prometheus-CSDN博客 因为篇幅原因&#xff0c;前面没有详细说明Prometheus的监控指标&…

小红书2024LLM论文分享

2024小红书大模型论文分享 BatchEval基于LLM评估LLM生成文本的质量 ACL2024 https://ypw0102.github.io/ 如果文本评价需要多个维度&#xff0c;需要调整BatchEval么&#xff1f; 目前是完整流程走一遍的&#xff0c;因此没有具体考虑细粒度。 评测连续的数据域&#xff0c;S…

使用飞书多维表格实现推送邮件

一、为什么用飞书&#xff1f; 在当今竞争激烈的商业环境中&#xff0c;选择一款高效、智能的办公工具至关重要。了解飞书的朋友应该都知道&#xff0c;飞书的集成能力是很强大的&#xff0c;能够与各种主流的办公软件无缝衔接&#xff0c;实现数据交互&#xff0c;提升工作效…