热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于go:支持SagaTccXa混用支持gRPCHTTP混用的分布式事务模式

Workflow模式是github.comdtm-labsdtm独创推出的模式,在这个模式下,能够混合应用XA、SAGA、TCC,也能够混合应用HTTP、gRPC,用户能够对分布式事务外面的

Workflow 模式是github.com/dtm-labs/dtm独创推出的模式,在这个模式下,能够混合应用XA、SAGA、TCC,也能够混合应用HTTP、gRPC,用户能够对分布式事务外面的绝大部分内容进行定制,具备极大的灵活性,上面咱们以转账场景,讲述如何在Workflow下进行实现。

workflow例子

Workflow模式下,既能够应用HTTP协定,也能够应用gRPC协定,上面以gRPC协定作为例子,一共分为一下几步:

  • 初始化 SDK
  • 注册workflow
  • 执行workflow

首先须要在应用workflow前对 SDK 的 Workflow 进行初始化:

import     "github.com/dtm-labs/dtmgrpc/workflow"

// 初始化workflow SDK,三个参数别离为:
// 第一个参数,dtm服务器地址
// 第二个参数,业务服务器地址
// 第三个参数,grpcServer
// workflow的须要从"业务服务器地址"+"grpcServer"上接管dtm服务器的回调
workflow.InitGrpc(dtmGrpcServer, busi.BusiGrpc, gsvr)

而后须要注册workflow的处理函数

wfName := "wf_saga"
err := workflow.Register(wfName, func(wf *workflow.Workflow, data []byte) error {
  req := MustUnmarshalReqGrpc(data)
  wf.NewBranch().OnRollback(func(bb *dtmcli.BranchBarrier) error {
    _, err := busi.BusiCli.TransOutRevert(wf.Context, req)
    return err
  })
  _, err := busi.BusiCli.TransOut(wf.Context, req)
  if err != nil {
    return err
  }
  wf.NewBranch().OnRollback(func(bb *dtmcli.BranchBarrier) error {
    _, err := busi.BusiCli.TransInRevert(wf.Context, req)
    return err
  })
  _, err = busi.BusiCli.TransIn(wf.Context, req)
  return err
})
  • 这个注册操作须要在业务服务启动之后执行,因为当过程crash,dtm会回调业务服务器,持续未实现的工作
  • 上述代码NewBranch会创立一个事务分支,一个分支会包含一个正向操作,以及全局事务提交/回滚时的回调
  • OnRollback/OnCommit会给以后事务分支指定全局事务回滚/提交时的回调,上述代码中,只指定了OnRollback,属于Saga模式
  • 这外面的 busi.BusiCli 须要增加workflow的拦截器,该拦截器会主动把rpc的申请后果记录到dtm,如下所示

    conn1, err := grpc.Dial(busi.BusiGrpc, grpc.WithUnaryInterceptor(workflow.Interceptor), nossl)
    busi.BusiCli = busi.NewBusiClient(conn1)

当然您也能够给所有的gRPC client增加workflow.Interceptor,这个中间件只会解决wf.Contextwf.NewBranchContext()下的申请

  • 当工作流函数返回nil/ErrFailure,全局事务会进入Commit/Rollback阶段,反序调用函数外部OnCommit/OnRollback注册的操作

最初是执行workflow

req := &busi.ReqGrpc{Amount: 30}
err = workflow.Execute(wfName, shortuuid.New(), dtmgimp.MustProtoMarshal(req))
  • 当Execute的后果为nil/ErrFailure时,全局事务已胜利/已回滚。
  • 当Execute的后果为其余值时,dtm服务器后续会回调这个工作流工作进行重试

workflow原理

workflow是如何保障分布式事务的数据一致性呢?当业务过程呈现crash等问题时,dtm服务器会发现这个workflow全局事务超时未实现,那么dtm会采纳指数回避的策略,对workflow事务进行重试。当workflow的重试申请达到业务服务,SDK会从dtm服务器读取全局事务的进度,对于已实现的分支,会将之前保留的后果,通过gRPC/HTTP等拦截器,间接返回分支后果。最终workflow会顺利完成。

工作流函数须要做到幂等,即第一次调用,或者后续重试,都该当取得同样的后果

Workflow下的Saga

Saga模式源自于这篇论文 SAGAS,其核心思想是将长事务拆分为多个短事务,由Saga事务协调器协调,如果每个短事务都胜利提交实现,那么全局事务就失常实现,如果某个步骤失败,则依据相同程序一次调用弥补操作。

在Workflow模式下,您能够在函数中,间接调用正向操作的函数,而后将弥补操作写到分支的OnRollback,那么弥补操作就会主动被调用,达到了Saga模式的成果

Workflow下的Tcc

Tcc模式源自于这篇论文 Life beyond Distributed Transactions:an Apostate’s Opinion,他将一个大事务分成多个小事务,每个小事务有三个操作:

  • Try 阶段:尝试执行,实现所有业务查看(一致性), 预留必须业务资源(准隔离性)
  • Confirm 阶段:如果所有分支的Try都胜利了,则走到Confirm阶段。Confirm真正执行业务,不作任何业务查看,只应用 Try 阶段预留的业务资源
  • Cancel 阶段:如果所有分支的Try有一个失败了,则走到Cancel阶段。Cancel开释 Try 阶段预留的业务资源。

对于咱们的 A 跨行转账给 B 的场景,如果采纳SAGA,在正向操作中调余额,在弥补操作中,反向调整余额,那
么会呈现以下状况:

  • A扣款胜利
  • A看到余额缩小,并通知B
  • 金额转入B失败,整个事务回滚
  • B始终收不到这笔资金

这样给AB单方带来了极大的困扰。这种状况在SAGA中无奈防止,然而能够通过TCC来解决,设计技巧如下:

  • 在账户中的 balance 字段之外,再引入一个 trading_balance 字段
  • Try 阶段查看账户是否被解冻,查看账户余额是否短缺,没问题后,调整 trading_balance (即业务上的冻结资金)
  • Confirm 阶段,调整 balance ,调整 trading_balance (即业务上的冻结资金)
  • Cancel 阶段,调整 trading_balance (即业务上的冻结资金)

这种状况下,一旦终端用户 A 看到本人的余额扣减了,那么 B 肯定可能收到资金

在Workflow模式下,您能够在函数中,间接调用Try操作,而后将Confirm操作写到分支的OnCommit,将Cancel操作写到分支的OnRollback,达到了Tcc模式的成果

Workflow下的XA

XA是由X/Open组织提出的分布式事务的标准,XA标准次要定义了(全局)事务管理器(TM)和(部分)资源管理器(RM)之间的接口。本地的数据库如mysql在XA中表演的是RM角色

XA一共分为两阶段:

第一阶段(prepare):即所有的参与者RM筹备执行事务并锁住须要的资源。参与者ready时,向TM报告已准备就绪。
第二阶段 (commit/rollback):当事务管理者(TM)确认所有参与者(RM)都ready后,向所有参与者发送commit命令。

目前支流的数据库根本都反对XA事务,包含mysql、oracle、sqlserver、postgre

在Workflow模式下,你能够在工作流函数中,调用NewBranch().DoXa来开启您的XA事务分支。

多种模式混合应用

在Workflow模式下,上述的Saga、Tcc、XA都是分支事务的模式,因而能够局部分支采纳一种模式,其余分支采纳另一种模式。这种混合模式带来的灵活性能够做到依据分支事务的个性抉择子模式,因而倡议如下:

  • XA:如果业务没有行锁争抢,那么能够采纳XA,这个模式须要的额定开发量比拟低,Commit/Rollback是数据库主动实现的。例如这个模式适宜创立订单业务,不同的订单锁定的订单行不同,相互之间并发无影响;不适宜扣减库存,因为波及同一个商品的订单都会争抢这个商品的行锁,会导致并发度低。
  • Saga:不适宜XA的一般业务能够采纳这个模式,这个模式额定的开发量比Tcc要少,只须要开发正向操作和弥补操作
  • Tcc:适宜一致性要求较高,例如后面介绍的转账,这个模式额定的开发量最多,须要开发包含Try/Confirm/Cancel

幂等要求

在Workflow模式下,当crash产生时,会进行重试,因而要求各个操作反对幂等,即第屡次调用和一次调用的后果是一样的,返回雷同的后果。业务中,通常采纳数据库的unique key来实现幂等,具体为insert ignore "unique-key",如果插入失败,阐明这个操作已实现,此次间接疏忽返回;如果插入胜利,阐明这是首次操作,持续后续的业务操作。

如果您的业务自身就是幂等的,那么您间接操作您的业务即可;如果您的业务为提供幂等性能,那么dtm提供了BranchBarrier辅助类,基于上述unique-key原理,能够不便的帮忙开发者实现在Mysql/Mongo/Redis中实现幂等操作。

以下两个是典型的非幂等操作,请留神:

  • 超时回滚:如果您的业务中有一个操作可能耗时长,并且您想要让您的全局事务在期待超时后,返回失败,进行回滚。那么这个就不是幂等操作,因为在极其状况下,两个过程同时调用了该操作,一个返回了超时失败,而另一个返回了胜利,导致后果不同
  • 达到重试下限后回滚:剖析过程同上。

Workflow模式暂未反对上述的超时回滚及重试达到下限后回滚,如果您有相干的场景需要,欢送把具体场景给咱们,咱们将踊跃思考是否增加这种的反对

分支操作后果

分支操作会返回以下几种后果:

  • 胜利:分支操作返回HTTP-200/gRPC-nil
  • 业务失败:分支操作返回HTTP-409/gRPC-Aborted,不再重试,全局事务须要进行回滚
  • 进行中:分支操作返回HTTP-425/gRPC-FailPrecondition,这个后果示意事务正在失常进行中,要求dtm重试时,不要采纳指数退却算法,而是采纳固定距离重试
  • 未知谬误 :分支操作返回其余后果,示意未知谬误,dtm会重试这个工作流,采纳指数退却算法

如果您的现有服务与上述的后果不同,那么您能够通过workflow.Options.HTTPResp2DtmError/GRPCError2DtmError来定制这部分后果

Saga的弥补操作、Tcc的Confirm/Cancel操作,依照Saga和Tcc的协定,是不容许返回业务上的失败,因为到了工作流的第二阶段Commit/Rollback,此时既不胜利,也不让重试,那么全局事务无奈实现,这点请开发者在设计时就要留神防止

事务实现告诉

局部业务场景,想要取得事务实现的告诉,这个性能能够通过在第一个事务分支上设置OnFinish回调来实现。当回调函数被调用时,所有的业务操作曾经执行结束,因而全局事务在本质上曾经实现。回调函数能够根据传入的isCommit来判断全局事务最终提交了还是回滚了。

有一个中央须要留神,收到OnFinish回调时,dtm服务器上,这个事务的状态还未修改为最终状态,因而如果混合应用事务实现告诉和查问全局事务后果,那么两者的后果可能不统一,倡议用户只应用其中一种形式,而不要混合应用。

性能

在DTM里,失常实现一个Workflow事务,须要两个离开的全局事务写(一个是Prepare时保留,另一个是将状态改为胜利),须要保留两头事务进度(这部分批量化后,开销很小)。比照DTM的Saga模式,少了一个独自的分支事务保留,另外分支事务的写入质变小(胜利的事务不须要额定保留弥补分支),因而性能会比Saga的性能更好,具体的测试报告,将来会出。

下一步工作

  • 逐步完善workflow的例子以及文档
  • 反对分支事务并发

分割咱们

欢送拜访咱们的我的项目,并star反对咱们:

https://github.com/dtm-labs/dtm

关注【分布式事务】公众号,取得更多分布式事务相干常识


推荐阅读
  • 图像因存在错误而无法显示 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • 本文讨论了在使用Git进行版本控制时,如何提供类似CVS中自动增加版本号的功能。作者介绍了Git中的其他版本表示方式,如git describe命令,并提供了使用这些表示方式来确定文件更新情况的示例。此外,文章还介绍了启用$Id:$功能的方法,并讨论了一些开发者在使用Git时的需求和使用场景。 ... [详细]
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
  • 像跟踪分布式服务调用那样跟踪Go函数调用链 | Gopher Daily (2020.12.07) ʕ◔ϖ◔ʔ
    每日一谚:“Acacheisjustamemoryleakyouhaven’tmetyet.”—Mr.RogersGo技术专栏“改善Go语⾔编程质量的50个有效实践” ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
  • MybatisPlus入门系列(13) MybatisPlus之自定义ID生成器
    数据库ID生成策略在数据库表设计时,主键ID是必不可少的字段,如何优雅的设计数据库ID,适应当前业务场景,需要根据需求选取 ... [详细]
  • Git GitHub多人协作
    在学校做一个小项目需要多人协作,就用到了gitHub,百度了一下多数写得乱七八糟或者支离破碎,于是总结了一下自己的步骤如下,第一次使用GitHUb,哪里不对望大神指出一.前期准备: ... [详细]
  • linux分区文件信息,Linux中国 文件分区
    在这篇文章中,我们来了解一些用来检查你的系统分区的一些命令,这些命令将检查每个磁盘的分区情况和其它细节,例如总空间容量,已用 ... [详细]
  • Iamworkingonaprojectwhichrequiresopentokandcallkitfornotifyingusers.However,theappli ... [详细]
  • 主从复制_mysql主从复制简介
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了mysql主从复制简介相关的知识,希望对你有一定的参考价值。  ... [详细]
author-avatar
MS07224_670
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有