Silky微服务框架在线文档Silky微服务框架在线文档
首页
文档
配置
源码解析
博文
github
gitee
首页
文档
配置
源码解析
博文
github
gitee
  • 启动时

    • 主机的构建
    • 服务引擎
    • 模块
    • 服务与服务条目的解析
    • Silky服务主机
    • 依赖注入约定
    • RPC 服务代理
  • 运行时

    • 终结点与路由
    • 执行器与调度
    • 本地执行器与服务端过滤器
    • 远程执行器与 RPC 调用
    • RPC 服务端消息处理
    • 服务治理
    • 缓存拦截器
    • 分布式事务(TCC)
    • HTTP 网关请求管道
    • 过滤器执行管道
    • Polly 弹性策略管道
    • 端点健康监控

概述

silky 框架提供了基于 TCC(Try-Confirm-Cancel) 模式的分布式事务支持。TCC 是一种应用层分布式事务解决方案:

  • Try:预留资源,执行业务检查和资源锁定
  • Confirm:确认执行,使用 Try 阶段预留的资源完成业务
  • Cancel:撤销执行,释放 Try 阶段预留的资源

相比两阶段提交(2PC),TCC 对底层资源(数据库、消息队列等)没有侵入性要求,适用于跨多个微服务的业务一致性场景。


使用方式

在服务接口方法上标注 [TccTransaction] 特性,并指定 Confirm 和 Cancel 的方法名:

public interface IAccountAppService
{
    /// <summary>
    /// Try 阶段:扣减账户余额(预留)
    /// </summary>
    [TccTransaction(ConfirmMethod = "DeductBalanceConfirm", CancelMethod = "DeductBalanceCancel")]
    Task<bool> DeductBalance(DeductBalanceInput input);

    /// <summary>
    /// Confirm 阶段:确认扣减(提交)
    /// </summary>
    Task<bool> DeductBalanceConfirm(DeductBalanceInput input);

    /// <summary>
    /// Cancel 阶段:恢复余额(回滚)
    /// </summary>
    Task<bool> DeductBalanceCancel(DeductBalanceInput input);
}

TccTransactionAttribute 的定义:

[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class TccTransactionAttribute : Attribute, ITccTransactionProvider
{
    public string ConfirmMethod { get; set; }  // Confirm 阶段的方法名
    public string CancelMethod { get; set; }   // Cancel 阶段的方法名
}

角色与流程

发起者(Starter)

发起者是 TCC 事务的入口,通常是业务流程的编排者(如订单服务)。发起者负责:

  1. 调用多个参与者的 Try 方法
  2. 所有 Try 成功后,触发全局 Confirm
  3. 任意 Try 失败时,触发全局 Cancel

参与者(Participant)

参与者是被发起者远程调用的微服务(如账户服务、库存服务)。每个参与者:

  1. 接收 Try 请求,预留资源
  2. 根据发起者的最终决定,执行 Confirm 或 Cancel

完整时序

订单服务(发起者)                 账户服务(参与者)       库存服务(参与者)
        │                               │                       │
        │── Try: DeductBalance ─────────▶                       │
        │── Try: ReduceStock ───────────────────────────────────▶
        │                               │                       │
    所有 Try 成功                                               
        │                               │                       │
        │── Confirm: DeductBalanceConfirm ────────────────────▶ │
        │── Confirm: ReduceStockConfirm ────────────────────────▶
        │                                                       │
    [如果任意 Try 失败]                                         
        │── Cancel: DeductBalanceCancel ──────────────────────▶ │
        │── Cancel: ReduceStockCancel ──────────────────────────▶

事务协调器(TccTransactionExecutor)

TccTransactionExecutor 是 TCC 事务的核心协调器,以单例懒加载(Lazy<T>)方式初始化:

public sealed class TccTransactionExecutor
{
    private static readonly Lazy<TccTransactionExecutor> _lazyExecutor =
        new(() => new TccTransactionExecutor(),
            LazyThreadSafetyMode.ExecutionAndPublication);

    public static TccTransactionExecutor Executor => _lazyExecutor.Value;
}

主要方法:

方法角色说明
PreTry(invocation)发起者创建事务记录,注册参与者,设置 Try 状态
PreTryParticipant(context, invocation)参与者注册参与者到事务,设置 Try 状态
GlobalConfirm(transaction)发起者遍历所有参与者,逐个调用 Confirm
GlobalCancel(transaction)发起者遍历所有参与者,逐个调用 Cancel
UpdateStartStatus(transaction)发起者更新事务状态为 Trying
Remove()通用清理当前线程的事务上下文

事务处理器

TransactionTccModule 通过命名注入注册了两个事务处理器:

// 发起者处理器
builder.RegisterType<StarterTccTransactionHandler>()
    .Named<ITransactionHandler>(TransactionRole.Start.ToString());

// 参与者处理器
builder.RegisterType<ParticipantTccTransactionHandler>()
    .Named<ITransactionHandler>(TransactionRole.Participant.ToString());

框架根据当前请求的 TransactionContext.TransactionRole 解析对应的处理器。

StarterTccTransactionHandler

发起者处理流程:

public async Task Handler(TransactionContext context, ISilkyMethodInvocation invocation)
{
    // 1. 创建事务,注册参与者(PreTry)
    var transaction = await executor.PreTry(invocation);
    SilkyTransactionHolder.Instance.Set(transaction);

    // 2. 传播事务上下文(通过 RpcContext Attachments 传递到下游)
    var transactionContext = new TransactionContext
    {
        Action = ActionStage.Trying,
        TransId = transaction.TransId,
        TransactionRole = TransactionRole.Start,
        TransType = TransactionType.Tcc
    };
    SilkyTransactionContextHolder.Instance.Set(transactionContext);

    try
    {
        // 3. 执行 Try 方法(其中会远程调用各参与者的 Try 逻辑)
        await invocation.ProceedAsync();
        transaction.Status = ActionStage.Trying;
        await executor.UpdateStartStatus(transaction);

        // 4. 所有 Try 成功 → 执行全局 Confirm
        await executor.GlobalConfirm(currentTransaction);
    }
    catch (Exception ex)
    {
        // 5. 任意 Try 失败 → 执行全局 Cancel
        await executor.GlobalCancel(errorCurrentTransaction);
        throw;
    }
    finally
    {
        SilkyTransactionContextHolder.Instance.Remove();
        executor.Remove();
    }
}

ParticipantTccTransactionHandler

参与者根据收到的 ActionStage 执行不同操作:

switch (context.Action)
{
    case ActionStage.Trying:
        // Try 阶段:执行预留资源逻辑,记录参与者
        participant = await _executor.PreTryParticipant(context, invocation);
        await invocation.ProceedAsync();
        break;

    case ActionStage.Confirming:
        // Confirm 阶段:从缓存或仓储加载参与者,执行 ConfirmMethod
        await _executor.ParticipantConfirm(invocation, participantList, context.ParticipantId);
        break;

    case ActionStage.Canceling:
        // Cancel 阶段:从缓存或仓储加载参与者,执行 CancelMethod
        await _executor.ParticipantCancel(invocation, participantList, context.ParticipantId);
        break;
}

事务上下文传播

TCC 事务上下文通过 RpcContext 的 Attachments(附件字典)在微服务间透传,与 HTTP Header 的传播机制类似:

发起者设置 TransactionContext
    │
    ▼(通过 RpcContext.Attachments 序列化到 TransportMessage)
DotNetty RPC 传输
    │
    ▼(参与者端从 Attachments 反序列化 TransactionContext)
参与者判断当前请求是否在事务中
    │
    ├── context.Action == Trying    → 执行业务,注册参与者
    ├── context.Action == Confirming → 执行 ConfirmMethod
    └── context.Action == Canceling  → 执行 CancelMethod

事务持久化(TransRepositoryStore)

事务状态通过 TransRepositoryStore 持久化,避免因服务重启导致事务数据丢失。默认实现基于 Redis(Silky.Transaction.Repository.Redis)。

持久化的核心对象:

对象说明
ITransaction全局事务记录:TransId、Status、Participants 列表
IParticipant参与者记录:ParticipantId、TransId、Role、Status、ConfirmMethod、CancelMethod

主要操作:

操作说明
CreateTransaction创建事务记录
CreateParticipant创建参与者记录
UpdateTransactionStatus更新事务状态(Trying → Confirming / Canceling)
UpdateParticipantStatus更新参与者状态
RemoveTransaction删除已完成的事务记录
LoadParticipant从仓储加载参与者(用于服务重启后的事务恢复)

事务恢复调度器

TccTransactionRecoveryService 是 TCC 的定期恢复调度器,以 ITransactionRecoveryService 的命名方式注册:

builder.RegisterType<TccTransactionRecoveryService>()
    .Named<ITransactionRecoveryService>(TransactionType.Tcc.ToString());

调度器定期扫描仓储中未完成的事务(状态为 Trying 或 Confirming/Canceling 的),重新触发 Confirm 或 Cancel,确保分布式事务最终一致性。


启用 TCC 事务

在服务宿主中引入 TransactionTccModule,并配置 Redis 仓储:

// 方式一:通过模块依赖
[DependsOn(typeof(TransactionTccModule))]
public class OrderHostModule : SilkyModule { }

// 方式二:使用扩展方法(如果框架提供)
services.AddTransactionTcc();

添加事务仓储(Redis):

services.AddRedisTransactionRepository(configuration);

注意事项

Warning

  1. Try 方法幂等性:Try 方法应保证幂等,因为在网络超时等异常情况下,框架可能重试 Try 请求。

  2. Confirm/Cancel 幂等性:Confirm 和 Cancel 方法必须保证幂等,调度器在恢复时可能重复执行。

  3. Cancel 方法的空回滚处理:Cancel 方法需要处理 Try 阶段未执行成功(资源未预留)时的空回滚情况,避免因 Cancel 方法读取不到预留数据而报错。

  4. 方法名约定:ConfirmMethod 和 CancelMethod 必须是同一接口中的方法名,且方法签名(参数列表)应与 Try 方法保持一致,以便框架正确调用。

  5. 事务传播范围:TCC 上下文通过 RpcContext.Attachments 自动传播,仅对 silky RPC 调用有效,不覆盖 HTTP 调用(HTTP 调用不参与 TCC 事务)。

编辑当前页
Prev
缓存拦截器
Next
HTTP 网关请求管道