百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

分布式事务系统Seata的这些安保机制是否会让你更放心

toyiye 2024-07-15 01:18 7 浏览 0 评论

一、背景

SpringBoot 项目,通过引入seata-spring-boot-starter来接入 Seata,Seata 的能力会通过 SpringBoot 的自动装配机制来引入。在学习的时候是梳理有什么强大的、科技感十足的能力,但在试点的时候则更多考虑的是有哪些安保机制,比如通过什么开关来启停某某功能,以保护程序。今天就梳理有什么安保机制,划清能力边界,让使用者不必太过担心;生产中安全永远是第一的嘛。

二、认知拉齐-starter 中提供什么能力

第二部分若真不熟悉,看不懂可跳过进入第三部分。

Pom 依赖

<dependency>
   <groupId>io.seata</groupId>
   <artifactId>seata-spring-boot-starter</artifactId>
   <version>${seata.version}</version>
</dependency>

梳理自动装配类,直接从seata-spring-boot-starter中找文件spring.factories,其中有以下自动装配类:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
io.seata.spring.boot.autoconfigure.SeataDataSourceAutoConfiguration,\
io.seata.spring.boot.autoconfigure.SeataAutoConfiguration,\
io.seata.spring.boot.autoconfigure.HttpAutoConfiguration,\
io.seata.spring.boot.autoconfigure.SeataSagaAutoConfiguration

1、SeataDataSourceAutoConfiguration

Seata 的 AT 和 AX 模式是基于数据源代理实现的,SeataDataSourceAutoConfiguration 中自动对数据源做了代理,不用使用者手动实现代理。

2、SeataAutoConfiguration

  • 构建全局事务扫描器GlobalTransactionScanner,注入到容器中,其内部做 2 件事情 会初始化 TM、RM 客户端 扫描Bean,对添加了全局事务注解的类(@GlobalTransactional、@GlobalLock、@TwoPhaseBusinessAction)生成代理对象,添加对应的拦截器(拦截器内补充分布式事务的能力)
  • 注入一个FailureHandler,其默认实现DefaultFailureHandlerImpl中只会打印错误日志,建议重写,异常发生时及时告知使用者。

3、HttpAutoConfiguration

应用通过 http 协议通信时,通过 http header 透传 xid

4、SeataSagaAutoConfiguration

Saga 模式才用的到,目前还不了解

三、探索 Seata 所提供的安保机制

3.1 引入 seata-spring-boot-starter 之后 Seata 功能就启动了嘛?

答案:不,有一个开关seata.enabled,若为 true:则启动自动装配;若为 false:则不启用自动装配。比如就在开发测试环境验证,暂且还不上生产,就可以通过这个开关来实现。

application.yml 中留意这个配置:

seata:
  enabled: true

上述几个自动装配类中都有激活条件,ConditionalOnProperty或 ConditionalOnExpression其用意为,当seata.enabled=true的情况下,自动装配类才生效。

@ConditionalOnProperty(prefix = SEATA_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
...
@ConditionalOnExpression("${seata.enabled:true}

3.2 数据源是被自动代理嘛?

答案 :不,有开关

seata.enableAutoDataSourceProxy:true,若为 true:则启动自动代理,若为 false:则不启用自动代理。

seata:
  enableAutoDataSourceProxy: true

生效源码见下方:

@ConditionalOnExpression("${seata.enabled:true} && ${seata.enableAutoDataSourceProxy:true} && ${seata.enable-auto-data-source-proxy:true}")
public class SeataDataSourceAutoConfiguration {

3.3 所有的数据源都会被代理嘛

答案:不,有两种办法来避免

方法 1:自动代理+排除法:

  • 开启自动代理seata.enableAutoDataSourceProxy:true
  • 指定不需要被代理的 DataSouce 的 bean 名称(数组形式)
seata:
    enableAutoDataSourceProxy: true
    excludesForAutoProxying: dataSource1,dataSource2,dataSource3

方法 2:手动代理

  • 关闭自动代理 seata.enableAutoDataSourceProxy:false
  • 手动方式对数据源做代理,参考这个代码
SeataDataSourceProxy buildProxy(DataSource origin, String proxyMode) {
if (BranchType.AT.name().equalsIgnoreCase(proxyMode)) {
    return new DataSourceProxy(origin);
}
if (BranchType.XA.name().equalsIgnoreCase(proxyMode)) {
    return new DataSourceProxyXA(origin);
}
throw new IllegalArgumentException("Unknown dataSourceProxyMode: " + proxyMode);
}

3.4 加了 Seata 事务注解就生效了嘛,被人不小心复制走的有办法不生效嘛

答案:算是有,目前已知有以下几种方法

方法 1: 可指定 Seata 注解扫描的包路径,根据情况结合 排除 bean 名称的方法一起用

// add scannable packages
GlobalTransactionScanner.addScannablePackages(seataProperties.getScanPackages());
// add excludeBeanNames
GlobalTransactionScanner.addScannerExcludeBeanNames(seataProperties.getExcludesForScanning());

方法 2:使用显式的编程 API 开启事务(待验证)

GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
try {
    tx.begin(300000, "test-group");
    accountService.addUserInfo(account.getAccountNo(),account.getAccountName(),account.getTip());
    storeService.decreaseStock(store);
    tx.commit();
} catch (TransactionException e) {
    try {
        tx.rollback();
    } catch (TransactionException transactionException) {
        transactionException.printStackTrace();
    }
    //e.printStackTrace();
}

3.5 Seata 的全局事务能力是否可以动态启停?

答案:可以

场景 1:先禁用再启用,可通过service.disableGlobalTransaction=true在启东时禁用,然后在运行期变更配置为 false ,如果配置中心能力够强,还可单独给某个实例激活全局事务。对应的源码如下

public void onChangeEvent(ConfigurationChangeEvent event) {
    if (ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION.equals(event.getDataId())) {
        disableGlobalTransaction = Boolean.parseBoolean(event.getNewValue().trim());
        //compareAndSet(expect, update), 要想更新成功的话,那么这个expect的值一定是1,否则是不会被更新的。
        //即配置中心下达启用分布式锁,且客户端未启动
        if (!disableGlobalTransaction && initialized.compareAndSet(false, true)) {
            LOGGER.info("{} config changed, old value:true, new value:{}", ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,
                    event.getNewValue());
            initClient();
            ConfigurationCache.removeConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION, this);
        }
    }
}

场景 2:在运行期关闭已运行的全局事务能力,可通过service.disableGlobalTransaction=true在运行期,关闭全局事务

3.6 Seata 是否有降级能力?

答案:有,有两个维度的降级能力,

方法 1:使用 3.5 中的是否禁用全局事务手动降级

方法 2:自动降级。配置个阈值,当自检周期(滑动时间窗口内)异常次数达到阈值后就禁用全局事务,当自检周期(滑动时间窗口内)连续成功后则恢复。通过设置client.tm.degradeCheck=true,结合degradeCheckAllowTimes 和 degradeCheckPeriod来设置阈值与自检周期;如下示例:

client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000

3.7 Seata 是否可以不代理无需分布式事务的数据源?

答案:可以变通实现,有 2 种方法。

方法 1:DataSouce 从一个变成 2 个,即一个是原始 DataSource,另一个基于原始的 DataSource 代理,生成一个代理的 DataSouce,在使用到分布式事务的逻辑中才使用代理的 DataSouce,不使用分布式事务的逻辑中使用原始的 DataSource。但这种两个 DataSouce 其实是同一个,会使用相同的连接池(用连接池的情况下)。

方法 2:使用两个完全独立的 DataSouce,其中一个做与分布式事务无关的逻辑;另一个做代理,提供分布式事务的能力。

3.8 Seata 的全局事务能力是否可以按请求属性启用

答案:可以有,这里提供 1 种方法。

把一个方法拆分,根据流量属性判断是否需要进入到开启分布式事务的方法中。

function A(param){
    if(param.xx == 开启分布式事务){
        A-2(param)
    }else{
        A-1(param)
    }
}
function A-1(param){
}
//A-2上添加分布式事务注解
fcuntion A-2(param){
}

四、总结

本篇梳理的内容是:当我们在试点分布式事务系统 Seata 的时候,对系统安全方面可能有哪些诉求,以及 Seata 能提供怎样的保护能力。毕竟我们引入新系统是为了解决问题而不是创造问题,没有足够使用经验,对内部机制掌握不够的情况下,全面的掌握 Seata 所提供的安保机制,按需禁用或开启、将新能力和老逻辑划清边界、以最小化测试单元的原则来推进,应该会更加顺利。

作者:Applehope
链接:https://juejin.cn/post/7172203910533218340
来源:稀土掘金

相关推荐

CryptoChat:一款功能强大的纯Python消息加密安全传输工具

关于CryptoChatCryptoChat是一款功能强大的纯Python消息加密安全传输工具,该工具专为安全研究专家、渗透测试人员和红蓝队专家设计,该工具可以完全保证数据传输中的隐私安全。该工具建立...

为什么都说Python简单,但我觉得难?

Python普遍被大家认为是编程语言中比较简单的一种,但有一位电子信息的学生说自己已经学了C语言,但仍然觉得Python挺难的,感觉有很多疑问,像迭代器、装饰器什么的……所以他提出疑问:Python真...

蓝牙电话-关联FreeSwitch中继SIP账号通过Rest接口

蓝牙电话-关联FreeSwitch中继SIP账号通过Rest接口前言上一篇章《蓝牙电话-与FreeSwitch服务器和UA坐席的通话.docx》中,我们使用开源的B2B-UA当中经典的FreeSWIT...

技术分享|Sip与WebRTC互通-SRProxy开源库讲解

SRProxy介绍目前WebRTC协议跟SIP协议互通场景主要运用在企业呼叫中心、企业内部通信、电话会议(PSTN)、智能门禁等场景,要想让WebRTC与SIP互通,要解决两个层面的...

全网第N篇SIP协议之GB28181注册 JAVA版本

鉴于网上大部分关于SIP注册服务器编写都是C/C++/python,故开此贴,JAVA实现也贴出分享GB28181定义了了基于SIP架构的视频监控互联规范,而对于多数私有协议实现的监控系统...

「linux专栏」top命令用法详解,再也不怕看不懂top了

在linux系统中,我们经常使用到的一个命令就是top,它主要是用来显示系统运行中所有的进程和进程对应资源的使用等信息,所有的用户都可以使用top命令。top命令内容量丰富,可令使用者头疼的是无法全部...

Linux 中借助 perf 对 php 程序模拟CPU高的案例分析

导语本文是一篇Linux借助工具分析CPU高的优化案例,没有任何干货内容,很详细的展示了优化CPU高的具体步骤,非常适合初中级读者阅读!...

centos漏洞处理方法(centos podman)

centos服务器最近有诸多漏洞,修复命令及对应的漏洞整理后,分享给大家RHSA-2020:1176-低危:avahi安全更新yumupdateavahi-libsRHSA-2017:326...

Linux上的free命令详解(Buffer和Cache)

解释一下Linux上free命令的输出。下面是free的运行结果,一共有4行。为了方便说明,我加上了列号。这样可以把free的输出看成一个二维数组FO(FreeOutput)。例如:FO[2][1]...

linux 命令行之你真的会用吗?--free 基本用法篇

free命令行统计内存使用率及swap交换分区的使用率数据。是由sourceforge负责维护的,在ubuntu上其包名为procps,这个源码包中,除了free还有ps,top,vmstat,ki...

kong api gateway 初体验(konga github)

kongapigateway初体验(firstsight?)。Kong是一个可扩展的开源API层(也称为API网关或API中间件)。Kong运行在任何RESTfulAPI的前面,并通过插件...

在Ubuntu下开启IP转发的方法(ubuntu20 ip)

IP地址分为公有ip地址和私有ip地址,PublicAddress是由INIC(internetnetworkinformationcenter)负责的,这些IP地址分配给了注册并向INIC提...

基于 Kubernetes 的 Serverless PaaS 稳定性建设万字总结

作者:许成铭(竞霄)数字经济的今天,云计算俨然已经作为基础设施融入到人们的日常生活中,稳定性作为云产品的基本要求,研发人员的技术底线,其不仅仅是文档里承诺的几个九的SLA数字,更是与客户切身利益乃...

跟老韩学Ubuntu Linux系列-sysctl 帮助文档

sysctl一般用于基于内核级别的系统调优,man帮助手册如下。...

如何在 Linux/Unix/Windows 中发现隐藏的进程和端口

unhide是一个小巧的网络取证工具,能够发现那些借助rootkit、LKM及其它技术隐藏的进程和TCP/UDP端口。这个工具在Linux、UNIX类、MS-Windows等操作系统下都...

取消回复欢迎 发表评论:

请填写验证码