• 分布式事务开源框架 提供跨数据库访问,分布式事务TCC、SAGA解决方案


    https://github.com/2881099/FreeSql.Cloud

    提供跨数据库访问,分布式事务TCC、SAGA解决方案。

     

     FreeSql.Cloud

    为 FreeSql 提供跨数据库访问,分布式事务TCC、SAGA解决方案,支持 .NET Core 2.1+, .NET Framework 4.0+.

    快速开始

    dotnet add package FreeSql.Cloud

    or

    Install-Package FreeSql.Cloud

    public enum DbEnum { db1, db2, db3 }
    
    var fsql = new FreeSqlCloud<DbEnum>("myapp"); //提示:泛型可以传入 string
    fsql.DistributeTrace = log => Console.WriteLine(log.Split('\n')[0].Trim());
    
    fsql.Register(DbEnum.db1, () => new FreeSqlBuilder()
        .UseConnectionString(DataType.Sqlite, @"Data Source=db1.db")
        .Build());
    
    fsql.Register(DbEnum.db2, () => new FreeSqlBuilder()
        .UseConnectionString(DataType.Sqlite, @"Data Source=db2.db")
        .Build());
    
    fsql.Register(DbEnum.db3, () => new FreeSqlBuilder()
        .UseConnectionString(DataType.Sqlite, @"Data Source=db3.db")
        .Build());

    FreeSqlCloud 必须定义成单例模式

    如何使用?

    FreeSqlCloud 的访问方式和 IFreeSql 一样:

    fsql.Select<T>();
    fsql.Insert<T>();
    fsql.Update<T>();
    fsql.Delete<T>();
    
    //...

    切换数据库:

    fsql.Change(DbEnum.db3).Select<T>();
    //以后所有 fsql.Select/Insert/Update/Delete 操作是 db3

    关于分布式事务

    1、简介

    FreeSqlCloud 提供 TCC/SAGA 分布式事务调度,遇错重试、程序重启不影响的事务单元管理功能。

    2、唯一标识

    FreeSqlCloud 使用唯一标识区分,达到事务管理互不冲突的目的,举例:

    var fsql = new FreeSqlCloud<DbEnum>("myapp");
    var fsql2 = new FreeSqlCloud<DbEnum>("myapp2");

    fsql2 访问不到 fsql 产生的事务,如果我们的 webapi 程序发布多实例,需要设置多个实例对应的 name,以作区分。

    3、主库

    fsql.Register 第一个注册的称之为【主库】,存储 TCC/SAGA 相关数据,当程序重新启动的时候,会将未处理完的事务载入内存重新调度。

    自动创建表 tcc_myapp、saga_myapp:

    提示:fsql2 会创建表 tcc_myapp2、saga_myapp2

    字段名描述
    tid 事务ID
    title 事务描述,查看日志更直观
    total 所有单元数量
    create_time 创建时间
    finish_time 完成时间
    status Pending, Confirmed, Canceled, ManualOperation
    max_retry_count 最大重试次数,如果仍然失败将转为【人工干预】
    retry_interval 重试间隔(秒)
    retry_count 已重试次数
    retry_time 重试时间

    自动创建表 tcc_myapp_unit、saga_myapp_unit:

    提示:fsql2 会创建表 tcc_myapp2_unit、saga_myapp2_unit

    字段名描述
    tid 事务ID
    index 单元下标,1到N
    description 单元描述,使用 [Description("xx")] 特性设置,查看日志更直观
    stage Try, Confirm, Cancel
    type_name 对应 c# TccUnit/SagaUnit 反射类型信息,用于创建 TccUnit/SagaUnit 对象
    state 状态数据
    state_type_name 状态数据对应的 c# 反射类型信息
    create_time 创建时间

    4、单元

    TccUnit、SagaUnit 内部支持调用 webapi/grpc,当调用异常触发重试调度。

    由于网络不确定因素,较坏的情况比如单元调用 webapi/grpc 成功,但是 tcc_unit 表保存状态失败,单元又会进入重试调用,最终导致多次调用 webapi/grpc,所以 web/grpc 提供方应该保证幂等操作,无论多少次调用结果都一致。

    TCC 事务

    var tid = Guid.NewGuid().ToString();
    await fsql
        .StartTcc(tid, "支付购买", 
            new TccOptions
            {
                MaxRetryCount = 10,
                RetryInterval = TimeSpan.FromSeconds(10)
            })
        .Then<Tcc1>(new LocalState { Id = 1, Name = "tcc1" })
        .Then<Tcc2>()
        .Then<Tcc3>(new LocalState { Id = 3, Name = "tcc3" })
        .ExecuteAsync();
    
    // 状态数据
    class LocalState
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    [Description("第1步")]
    class Tcc1 : TccUnit<LocalState>
    {
        public override Task Cancel() => throw new Exception("dkdkdk");
        public override Task Confirm() => Task.CompletedTask;
        public override Task Try() => Task.CompletedTask;
    }
    [Description("第2步")]
    class Tcc2 : TccUnit<LocalState>
    {
        public override Task Cancel() => Task.CompletedTask;
        public override Task Confirm() => Task.CompletedTask;
        public override Task Try() => Task.CompletedTask;
    }
    [Description("第3步")]
    class Tcc3 : TccUnit<LocalState>
    {
        public override Task Cancel() => Task.CompletedTask;
        public override Task Confirm() => Task.CompletedTask;
        public override Task Try() => throw new Exception("xxx");
    }

    执行结果:

    2020-12-02 14:03:34 【myapp】db1 注册成功, 并存储 TCC/SAGA 事务相关数据
    2020-12-02 14:07:31 【myapp】成功加载历史未完成 TCC 事务 0 个
    2020-12-02 14:07:31 【myapp】成功加载历史未完成 SAGA 事务 0 个
    2020-12-02 14:03:35 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Created successful, retry count: 10, interval: 10S
    2020-12-02 14:03:35 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) TRY successful
    2020-12-02 14:03:35 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit2(第2步) TRY successful
    2020-12-02 14:03:35 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit3(第3步) TRY failed, ready to CANCEL, -ERR xxx
    2020-12-02 14:03:35 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit2(第2步) CANCEL successful
    2020-12-02 14:03:35 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed , -ERR dkdkdk
    2020-12-02 14:03:45 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 1 times , -ERR dkdkdk
    2020-12-02 14:03:55 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 2 times , -ERR dkdkdk
    2020-12-02 14:04:06 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 3 times , -ERR dkdkdk
    2020-12-02 14:04:16 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 4 times , -ERR dkdkdk
    2020-12-02 14:04:26 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 5 times , -ERR dkdkdk
    2020-12-02 14:04:36 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 6 times , -ERR dkdkdk
    2020-12-02 14:04:46 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 7 times , -ERR dkdkdk
    2020-12-02 14:04:57 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 8 times , -ERR dkdkdk
    2020-12-02 14:05:07 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 9 times , -ERR dkdkdk
    2020-12-02 14:05:17 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Unit1(第1步) CANCEL failed retry again 10 times , -ERR dkdkdk
    2020-12-02 14:05:17 【myapp】TCC (5fec6379-d43e-4d5f-95a2-42ea8710f176, 支付购买) Not completed, waiting for manual operation 【人工干预】

    Saga 事务

    var tid = Guid.NewGuid().ToString();
    await fsql
        .StartSaga(tid, "发表评论", 
            new SagaOptions
            {
                MaxRetryCount = 5,
                RetryInterval = TimeSpan.FromSeconds(5)
            })
        .Then<Saga1>(new LocalState { Id = 1, Name = "tcc1" })
        .Then<Saga2>()
        .Then<Saga3>(new LocalState { Id = 3, Name = "tcc3" })
        .ExecuteAsync();
    
    // 状态数据
    class LocalState
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    [Description("第1步")]
    class Saga1 : SagaUnit<LocalState>
    {
        public override Task Cancel() => throw new Exception("dkdkdk");
        public override Task Commit() => Task.CompletedTask;
    }
    [Description("第2步")]
    class Saga2 : SagaUnit<LocalState>
    {
        public override Task Cancel() => Task.CompletedTask;
        public override Task Commit() => Task.CompletedTask;
    }
    [Description("第3步")]
    class Saga3 : SagaUnit<LocalState>
    {
        public override Task Cancel() => Task.CompletedTask;
        public override Task Commit() => throw new Exception("xxx");
    }

    执行结果:

    2020-12-02 14:07:30 【myapp】db1 注册成功, 并存储 TCC/SAGA 事务相关数据
    2020-12-02 14:07:31 【myapp】成功加载历史未完成 TCC 事务 0 个
    2020-12-02 14:07:31 【myapp】成功加载历史未完成 SAGA 事务 0 个
    2020-12-02 14:07:31 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Created successful, retry count: 5, interval: 5S
    2020-12-02 14:07:31 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit1(第1步) COMMIT successful
    2020-12-02 14:07:31 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit2(第2步) COMMIT successful
    2020-12-02 14:07:31 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit3(第3步) COMMIT failed, ready to CANCEL, -ERR xxx
    2020-12-02 14:07:31 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit2(第1步) CANCEL successful
    2020-12-02 14:07:31 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit1(第1步) CANCEL failed, -ERR dkdkdk
    2020-12-02 14:07:36 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit1(第1步) CANCEL failed after 1 retries, -ERR dkdkdk
    2020-12-02 14:07:41 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit1(第1步) CANCEL failed after 2 retries, -ERR dkdkdk
    2020-12-02 14:07:47 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit1(第1步) CANCEL failed after 3 retries, -ERR dkdkdk
    2020-12-02 14:07:52 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit1(第1步) CANCEL failed after 4 retries, -ERR dkdkdk
    2020-12-02 14:07:57 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Unit1(第1步) CANCEL failed after 5 retries, -ERR dkdkdk
    2020-12-02 14:07:57 【myapp】SAGA(e5469b8f-c27f-498a-a0f8-6dd128967dca, 发表评论) Not completed, waiting for manual
  • 相关阅读:
    Xilinx之软件平台 ISE与Vivado前世今生
    博客开园
    第一天:开始你的Jobeet项目
    MySQL之alter语句用法总结
    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
    MySQL中distinct和group by性能比较[转]
    GROUP BY,WHERE,HAVING之间的区别和用法
    split(),preg_split()与explode()函数分析与介
    解析posix与perl标准的正则表达式区别
    sql关键字的解释执行顺序
  • 原文地址:https://www.cnblogs.com/lhxsoft/p/15752385.html
Copyright © 2020-2023  润新知