Spring Cloud Alibaba Seata 源码分析-数据源代理

AT模式的核心点:

  1. 获取全局锁、开启全局事务
  2. 解析SQL并写入undolog

分析AT模式如何解析SQL并写入undolog,首先我们要先明确实际上Seata其中采用了数据源代理的模式。

那么这个就需要我们在回顾一下GlobalTransactionScanner这个类型,在这个类型中继承了一些的接口和抽象类,比较关键的几个:

  • AbstractAutoProxyCreator
  • InitializingBean
阅读更多

Spring Cloud Alibaba Seata 源码分析 服务端(TC)源码解读

服务端表解释

我们的Seata服务端在应用的时候需要准备三张表,那么这三张表分别代表的意思就是

  1. branch_table 分支事务表
  2. global_table 全局事务表
  3. lock_table 全局锁表

客户端请求服务端以后,我们就需要把对应的全局事务包括分支事务和全局锁全部存放到这里。

![image.png](spring-cloud-alibaba-seata-source-code-analysis-server (-tc)-source-code-interpretation/a1cca08a47184ea5b4d1a2ba1cb12b5e.png)

阅读更多

Spring Cloud Alibaba Seata 2PC 核心源码解读

2PC提交源码流程

GlobalTransactionalInterceptor全局事务拦截器,一旦执行拦截器,就会进入到其中的invoke方法,在这其中会做一些@GlobalTransactional注解的判断,如果有注解以后,会执行全局事务和全局锁,那么在执行全局事务的时候会调用handleGlobalTransaction全局事务处理器,这里主要是获取事务信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
Object handleGlobalTransaction(final MethodInvocation methodInvocation,
final GlobalTransactional globalTrxAnno) throws Throwable {
boolean succeed = true;
try {
return transactionalTemplate.execute(new TransactionalExecutor() {
@Override
public Object execute() throws Throwable {
return methodInvocation.proceed();
}

// 获取事务名称,默认获取方法名
public String name() {
String name = globalTrxAnno.name();
if (!StringUtils.isNullOrEmpty(name)) {
return name;
}
return formatMethod(methodInvocation.getMethod());
}

/**
* 解析GlobalTransactional注解属性,封装为对象
* @return
*/
@Override
public TransactionInfo getTransactionInfo() {
// reset the value of timeout
// 获取超时时间,默认60秒
int timeout = globalTrxAnno.timeoutMills();
if (timeout <= 0 || timeout == DEFAULT_GLOBAL_TRANSACTION_TIMEOUT) {
timeout = defaultGlobalTransactionTimeout;
}

// 构建事务信息对象
TransactionInfo transactionInfo = new TransactionInfo();
transactionInfo.setTimeOut(timeout);// 超时时间
transactionInfo.setName(name()); // 事务名称
transactionInfo.setPropagation(globalTrxAnno.propagation());// 事务传播
transactionInfo.setLockRetryInternal(globalTrxAnno.lockRetryInternal());// 校验或占用全局锁重试间隔
transactionInfo.setLockRetryTimes(globalTrxAnno.lockRetryTimes());// 校验或占用全局锁重试次数
Set<RollbackRule> rollbackRules = new LinkedHashSet<>();
// 其他构建信息
for (Class<?> rbRule : globalTrxAnno.rollbackFor()) {
rollbackRules.add(new RollbackRule(rbRule));
}
for (String rbRule : globalTrxAnno.rollbackForClassName()) {
rollbackRules.add(new RollbackRule(rbRule));
}
for (Class<?> rbRule : globalTrxAnno.noRollbackFor()) {
rollbackRules.add(new NoRollbackRule(rbRule));
}
for (String rbRule : globalTrxAnno.noRollbackForClassName()) {
rollbackRules.add(new NoRollbackRule(rbRule));
}
transactionInfo.setRollbackRules(rollbackRules);
return transactionInfo;
}
});
} catch (TransactionalExecutor.ExecutionException e) {
// 执行异常
TransactionalExecutor.Code code = e.getCode();
switch (code) {
case RollbackDone:
throw e.getOriginalException();
case BeginFailure:
succeed = false;
failureHandler.onBeginFailure(e.getTransaction(), e.getCause());
throw e.getCause();
case CommitFailure:
succeed = false;
failureHandler.onCommitFailure(e.getTransaction(), e.getCause());
throw e.getCause();
case RollbackFailure:
failureHandler.onRollbackFailure(e.getTransaction(), e.getOriginalException());
throw e.getOriginalException();
case RollbackRetrying:
failureHandler.onRollbackRetrying(e.getTransaction(), e.getOriginalException());
throw e.getOriginalException();
default:
throw new ShouldNeverHappenException(String.format("Unknown TransactionalExecutor.Code: %s", code));
}
} finally {
if (degradeCheck) {
EVENT_BUS.post(new DegradeCheckEvent(succeed));
}
}
}
阅读更多

Spring Cloud Alibaba Seata 源码入口

Seata客户端启动

首先一个Seata的客户端启动一般分为几个流程:

  1. 自动加载各种Bean及配置信息
  2. 初始化TM
  3. 初始化RM(具体服务)
  4. 初始化分布式事务客户端完成,代理数据源
  5. 连接TC(Seata服务端),注册RM,注册TM
  6. 开启全局事务

在这个其中,就会涉及到几个核心的类型,首先我们需要来看配置类型GlobalTransactionAutoConfiguration

阅读更多

Spring Cloud Alibaba Sentinel 源码分析-滑动时间窗口算法原理

“滑动时间窗口算法” 是Sentinel源码中的一个非常重要的算法。

image-20211222170933011

时间窗算法

那么在了解滑动时间窗算法之前,我们先要来了解时间窗算法,也可以称之为:固定时间窗算法

概念:固定时间窗口计数器算法思想:在固定的时间窗口内,可以允许固定数量的请求进入。超过数量就拒绝或者排队,等下一个时间段进入。

阅读更多

Spring Cloud Alibaba Sentinel DegradeSlot 源码解析

DegradeSlot是熔断降级的Slot,那我们直接来看核心方法

1
2
3
4
5
6
7
8
9
//DegradeSlot.entry
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
// 熔断降级检测
performChecking(context, resourceWrapper);
// 触发下一个节点
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
阅读更多

Spring Cloud Alibaba Sentinel StatisticSlot 源码解析

StatisticSlot定义:

StatisticSlot 是 Sentinel 最为重要的类之一,用于根据规则判断结果进行相应的统计操作。

entry 的时候:依次执行后面的判断 slot。每个 slot 触发流控的话会抛出异常(BlockException的子类)。若有 BlockException抛出,则记录 block 数据;若无异常抛出则算作可通过(pass),记录 pass 数据。

exit 的时候:若无 error(无论是业务异常还是流控异常),记录 complete(success)以及 RT,线程数-1。

阅读更多