Sentinel服务保护 + Seata分布式事务

服务保护

雪崩问题】微服务调用链路中某个服务,引起整个链路中所有微服务都不可用。在这里插入图片描述
原因】:

  1. 微服务相互调用,服务提供者出现故障。
  2. 服务调用这没有做好异常处理,导致自身故障。
  3. 调用链中所有服务级联失败,导致整个集群故障。

解决方案】:
请求限流、线程隔离、服务熔断
服务保护技术】:
在这里插入图片描述

Sentinel服务保护

官方文档:Sentinel

使用步骤

1. 使用docker部署sentinel

创建并运行sentinel容器:

docker run -d \
--net=host \
--name sentinel \
--restart=always \
-e AUTH_USERNAME=admin \
-e AUTH_PASSWORD=admin \
bladex/sentinel-dashboard:1.8.6

完成后在浏览器输入:192.168.140.101:8858,用户名admin,密码admin

2.在微服务中连接sentinel控制台

引入sentinel依赖:

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

配置控制台:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.140.101:8858 # sentinel的控制台地址
      http-method-specify: true # 开启请求方式前缀

Restful风格的API请求路径一般相同,会导致簇点资源名称重复。所以我们要修改配置,把请求方式 + 请求路径作为簇点资源名称

簇点链路

簇点链路就是单机调用链路,是一次请求进入服务后经过的每一个被Sentinel监控的资源链。默认Sentinel会监控SpringMVC的每一个Endpoint(Http接口)。限流、熔断等都是争对簇点链路中的资源设置的,资源名默认就是接口的请求路径。
在这里插入图片描述

解决方案

1. 请求限流

限制访问微服务的请求的并发量,避免服务因流量激增而出现故障。
在这里插入图片描述
在这里插入图片描述
这个接口每秒钟只能处理6个请求,使用ApiFox进行测试,会有部分请求失败【失败返回状态码429】。
在这里插入图片描述

2. 线程隔离

通过限定每个业务能使用的线程数量而将故障业务隔离,避免故障扩散。
在这里插入图片描述
场景】:假设有大量的查询购物车的请求,通过对查询购物车这个线程做线程隔离,可以保证购物车这个微服务的资源不会被耗尽,不会对修改购物车等其他业务造成影响。
在这里插入图片描述
在这里插入图片描述

线程隔离和请求限流的区别:
请求限流:控制接受请求的速度(每秒访问几次)
线程隔离:控制最多能接收请求的次数(一次访问的线程数)
就算请求限流设置的再慢,如果线程卡住的话,不设置线程隔离,也会导致资源占用。

3. fallback

在这里插入图片描述
一、 将FeignClient作为Sentinel的簇点资源:

feign:
  sentinel:
    enabled: true # 开启流量控制

二、 为FeignClient添加Fallback:

  • 方法1:FallbackClass,无法对远程调用的异常做处理
  • 方法2:FallbackFactory,可以对远程调用的异常做处理
  1. 自定义类,实现FallbackFactory,编写对某个FeignClient的fallback逻辑:
@Slf4j
public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> {
    @Override
    public ItemClient create(Throwable cause) {
    	// 编写失败的处理逻辑(失败后就会走里边的方法)
        return new ItemClient() {
            @Override
            public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
                log.error("查询商品失败,"+ cause);
                return CollUtils.emptyList();
            }

            @Override
            public void deductStock(List<OrderDetailDTO> items) {
                log.error("扣减商品库存失败,"+ cause);
                throw new RuntimeException(cause);
            }
        };
    }
}
  1. 将定义的FallbackFactory注册为一个Bean:
public class DefaultFeignConfig {
	@Bean
	public ItemClientFallbackFactory itemClientFallbackFactory() {
		return new ItemClientFallbackFactory();
	}
}
  1. 在ItemClient接口中使用FallbackFactory:@FeignClient(value = "item-service", fallbackFactory = ItemClientFallbackFactory.class)
@FeignClient(value = "item-service", fallbackFactory = ItemClientFallbackFactory.class)
public interface ItemClient {
    @GetMapping("/items")
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);

    @PutMapping("/items/stock/deduct")
    void deductStock(@RequestBody List<OrderDetailDTO> items);
}

在这里插入图片描述

4. 服务熔断

断路器统计请求的异常比例或慢调用比例,如果超出阈值则会熔断该业务,则拦截改接口的请求。熔断期间,所有请求快速失败,全部走fallback逻辑。当服务恢复时,断路器会放行访问该服务的请求。
在这里插入图片描述

断路器工作原理:

在这里插入图片描述
默认情况:Closed状态
如果失败的比例过高:就会进入Open状态【拦截一切请求,快速失败】
Open状态下会尝试放行一次请求,进入Half-Open状态,如果仍然失败,再次返回Open状态;如果成功,回到Closed状态

配置熔断策略

在这里插入图片描述
在这里插入图片描述

分布式事务

如果一个业务需要多个服务合作完成,而且每个服务都有事务,多个事务必须同时成功或同时失败,这样的事务就是分布式事务。其中每一个服务的事务就是一个分支事务。整个业务称为全局事务
场景】:用户下单后,订单服务首先创建订单,随后调用购物车服务清理购物车,最后调用库存服务扣减商品的库存。如果在调用库存服务的时候商品库存为0,此时扣减库存失败,订单服务和购物车服务应该同时失败。
在这里插入图片描述
出现问题的原因】:各个分支服务不知道对方的情况
解决思路】:让各个分支事务感受到对方的存在,让所有的微服务向事务协调者报告当前的状态。
在这里插入图片描述

Seata架构

  • 事务协调者(TC):维护全局和分支事务的状态,协调全局事务提交或回滚。
  • 事务管理器(TM):定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • 资源管理器(RM):管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态。
    在这里插入图片描述

1. 部署TC服务

  1. 创建数据库,导入sql文件
    在这里插入图片描述
CREATE DATABASE IF NOT EXISTS `seata`;
USE `seata`;


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;


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;


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_and_branch_id` (`xid` , `branch_id`)
) 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);
  1. 准备配置文件
    seata运行时所需的配置文件
    上传前先看看application.yml,里边可能有些配置需要改一下
    把上边的配置文件丢到root根目录下
    在这里插入图片描述
  2. docker部署
    在/root目录下执行以下命令,创建并允许seata容器
docker run --name seata \
-p 8099:8099 \
-p 7099:7099 \
-e SEATA_IP=192.168.140.101 \
-v ./seata:/seata-server/resources \
--privileged=true \
--network hm-net \
--restart=always \
-d \
seataio/seata-server:1.5.2
  1. 以上操作都完成后,在浏览器输入:http://192.168.140.101:7099/后即可登录seata控制台。(初始账号:admin、密码:admin)

2. 微服务集成Seata

  1. 引入Seata依赖
<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
  1. 配置TC服务地址,让微服务找到TC服务地址
    在这里插入图片描述
seata:
  registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
    type: nacos # 注册中心类型 nacos
    nacos:
      server-addr: 192.168.140.101:8848 # nacos地址
      namespace: "" # namespace,默认为空
      group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP
      application: seata-server # seata服务名称
      username: nacos
      password: nacos
  tx-service-group: hmall # 事务组名称
  service:
    vgroup-mapping: # 事务组与tc集群的映射关系
      hmall: "default"

因为很多服务都需要实现分布式事务,所以可以把对于seata的配置抽取成一个共享配置写在nacos里。所以添加依赖的时候,检查一下是否有bootstrapnacos配置管理的依赖。

查看seata的日志文件,可以看到购物车服务、交易服务、商品服务已经全部和seata的TC服务建立连接。
在这里插入图片描述

3. Seata解决分布式事务问题

XA模式—强一致

在这里插入图片描述

  1. 一阶段工作:
  • RM注册分支事务
  • RM执行分支事务sql但不提交
  • RM报告执行状态到TC
  1. 二阶段工作:
  • TC检测各分支事务执行状态:
    • 如果都成功,通知所有RM提交事务
    • 如果有失败,通知所有RM回滚事务
  • RM接收到TC指令,提交或回滚事务

通过“等待”的方式,确保了全局事务的ACID特性。但是一阶段需要锁定数据库的资源,到二阶段才释放,性能差。

实现步骤
  1. 修改(每个参与事务的微服务)application.yml文件,开启XA模式
seata:
  data-source-proxy-mode: XA
  1. 给发起全局事务的入口添加@GlobalTransactional注解
    在这里插入图片描述

AT模式(主推)—最终一致

AT模式弥补了XA模式中资源锁定周期过长的缺陷。
在这里插入图片描述

  1. 一阶段RM的工作:
  • 注册分支事务
  • 记录undo-log(数据快照)
  • 执行业务sql并提交
  • 报告事务状态
  1. 二阶段提交时RM的工作:
  • 删除undo-log即可
  1. 二阶段回滚时RM的工作:
  • 根据undo-log恢复数据到更新前

AT模式相比于XA模式的优点在于:在一阶段不需要等待彼此执行,而是各自提交,这样资源就没有锁定,性能也会好。
但是如果二阶段需要进行回滚,在回滚之前,会出现数据短暂的不一致。
AT模式与XA模式的区别】:

  1. XA模式一阶段不提交事务,锁定资源
    AT模式一阶段直接提交,不锁定资源
  2. XA模式依赖数据库机制实现回滚
    AT模式利用数据快照实现回滚
  3. XA模式强一致
    AT模型最终一致
实现步骤
  1. 创建数据表,导入用来记录数据快照的undo_log表
    】:每个分支事务都需要有自己的undo_log表
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) 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 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
  1. 修改application.yml文件,将事务模式修改为AT模式
seata:
  data-source-proxy-mode: AT

在这里插入图片描述
数据快照(undo_log表):
在这里插入图片描述

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

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

相关文章

六、Angular 发送请求/ HttpClient 模块

一、应用 HttpClient 模块 angular/common/http 中的 HttpClient 类基于浏览器提供的 XMLHttpRequest 接口。要想使用 HtpClient 模块&#xff0c;就要先导入 Anqular 的 HttpClientModule。大多数 Web 应用程序都会在根模块 AppModule 中导入它。 编辑 src/app/app.module.ts…

CompletableFuture // todo

相比较所有代码都在主线程执行&#xff0c;使用Future的好处&#xff1a;利用服务器多核、并发的优势。 不足&#xff1a; 开启没有返回值的异步线程&#xff1a; 1、runAsync 使用lambda表达式&#xff1a; 开启有返回值的异步线程&#xff1a; 1、supplyAsync 异步任务中的…

css面试常考布局(圣杯布局、双飞翼布局、三栏布局、两栏布局、三角形)

两栏布局 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head> &…

arcgisPro加载天地图(CGCS2000)影像

1、注册天地图账号&#xff1b; 2、申请key&#xff1b; 3、添加WMTS服务器。 这里已经办好了前两步&#xff0c;下面详细介绍最后一步。 添加WMTS服务器。 在天地图网站&#xff0c;找到如下页面&#xff0c; 复制网址&#xff0c;如&#xff1a;http://t0.tianditu.gov.cn…

继承(7)

大家好&#xff0c;今天我们继续来学习一下继承的知识&#xff0c;这方面需要大家勤动脑才能理解&#xff0c;那么我们来看。 1.9 protected关键字 在类和对象章节中&#xff0c;为了实现封装特性,java中引入访向限定符,主要限定:类或者类中成员能否在类外和其他包中被访问. …

ModuleNotFoundError: No module named ‘podm.metrics‘报错等解决方法

ModuleNotFoundError: No module named podm.metrics’报错等解决方法 podm.metrics 在运行时报错&#xff1a; ModuleNotFoundError: No module named ‘podm.metrics’ 安装了podm后还是报错 解决方法&#xff1a; 查看安装位置 查看podm的安装位置&#xff0c;并打开到该…

HDFS异构存储和存储策略

一、HDFS异构存储类型 1.1 冷、热、温、冻数据 通常&#xff0c;公司或者组织总是有相当多的历史数据占用昂贵的存储空间。典型的数据使用模式是新传入的数据被应用程序大量使用&#xff0c;从而该数据被标记为"热"数据。随着时间的推移&#xff0c;存储的数据每周…

sklearn-逻辑回归-制作评分卡

目录 数据集处理 分箱 分多少个箱子合适 分箱要达成什么样的效果 对一个特征进行分箱的步骤 分箱的实现 封装计算 WOE 值和 IV值函数 画IV曲线&#xff0c;判断最佳分箱数量 结论 pd.qcut 执行报错 功能函数封装 判断分箱个数 在银行借贷场景中&#xff0c;评分卡是…

中学综合素质笔记3

第一章职业理念 第三节 教师观 考情提示&#xff1a; 单选题材料分析题 学习要求&#xff1a; 理解、 识记、 运用 &#xff08;一&#xff09;教师职业角色的转变&#xff08;单选材料分析&#xff09; 从教师与学生的关系看——对学生 新课程要求教师应该是学生学习的引…

【Linux】设备驱动中的ioctl详解

在Linux设备驱动开发中&#xff0c;ioctl&#xff08;输入输出控制&#xff09;是一个非常重要的接口&#xff0c;用于用户空间应用程序与内核空间设备驱动之间进行通信。通过ioctl&#xff0c;应用程序可以发送命令给设备驱动&#xff0c;控制设备的行为或获取设备的状态信息。…

linux上使用cmake编译的方法

一、hello 例程仅基于一个cpp文件 C文件或工程进行编译时可以使用g指令&#xff08;需要对每一个程序和源文件分别使用g指令编译&#xff09;&#xff0c;当程序变大时&#xff0c;一个工程文件往往会包含很文件夹和源文件&#xff0c;这时我们需要的编译指令将越来越长&#…

(vue)el-table-column type=“selection“表格选框怎么根据条件添加禁选

(vue)el-table-column type"selection"表格选框怎么根据条件添加禁选 html <el-table:data"tableData"style"width: 100%"><el-table-columntype"selection"width"55":selectable"checkSelectable">…

linux nginx 安装后,发现SSL模块未安装,如何处理?

&#x1f468;‍⚕ 主页&#xff1a; gis分享者 &#x1f468;‍⚕ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕ 收录于专栏&#xff1a;运维工程师 文章目录 前言SSL模块安装 前言 nginx 安装后&#xff0c;发现SSL模块未安装&…

kubeneters-循序渐进Cilium网络(二)

文章目录 概要IP 地址配置接口配置解析结论 概要 接续前一章节&#xff0c;我们还是以这张图继续深入Cilium网络世界 IP 地址配置 通过检查 Kubernetes 集群的当前环境&#xff0c;可以获取实际的 IP 地址和配置信息。这些信息将被补充到之前的网络示意图中&#xff0c;以使…

虚拟机使用MQ及介绍

mq官网&#xff1a;https://www.rabbitmq.com 一、虚拟机与 MQ 的结合优势 隔离与安全&#xff1a;虚拟机为 MQ 的运行提供了一个独立的环境&#xff0c;与宿主机以及其他虚拟机相互隔离。这意味着即使 MQ 所在的虚拟机出现故障或遭受安全威胁&#xff0c;也不会直接影响到宿主…

比亚迪夏直插家用MPV腹地,“迪王”开启全面销冠新征程

文/王俣祺 导语&#xff1a;比亚迪前脚刚收获2024年的全面成功&#xff0c;后脚立刻就开始布局2025年的产品矩阵了。比亚迪夏的横空出世&#xff0c;看来家用MPV市场也要感受“迪王”的恐怖如斯了。 家用MPV市场的“意外之喜” 1月8日&#xff0c;比亚迪夏终于在万众瞩目之下…

c++入门之 命名空间与输入输出

1、命名空间 1.1使用命名空间的原因 先看一个例子&#xff1a; #include <iostream>int round 0;int main() {printf("%d", round);return 0; }请问&#xff0c;这个程序能跑起来吗&#xff1f; 答案是否定的 原因是&#xff0c;当我们想创建一个全局变量 …

php 使用simplexml_load_string转换xml数据格式失败

本文介绍如何使用php函数解析xml数据为数组。 <?php$a <xml><ToUserName><![CDATA[ww8b77afac71336111]]></ToUserName><FromUserName><![CDATA[sys]]></FromUserName><CreateTime>1736328669</CreateTime><Ms…

12 USART串口通讯

1 串口物理层 两个设备的“DB9接口”之间通过串口信号建立连接&#xff0c;串口信号线中使用“RS232标准”传输数据信号。由于RS232电平标准的信号不能直接被控制器直接识别&#xff0c;所以这些信号会经过“电平转换芯片”转换成控制器能识别的“TTL校准”的电平信号&#xff…

FreePBX 17 on ubuntu24 with Asterisk 20

版本配置&#xff1a; FreePBX 17&#xff08;最新&#xff09; Asterisk 20&#xff08;最新Asterisk 22&#xff0c;但是FreePBX 17最新只支持Asterisk 21&#xff0c;但是21非LTS版本&#xff0c;所以选择Asterisk 20&#xff09; PHP 8.2 Maria DB (v10.11) Node J…