seata使用体验

Seata 是一站式的分布事务的解决方案,提供四种事务模式:

  • AT 模式
  • TCC 模式
  • Saga 模式
  • XA 模式

Seata将一个分布式事务看作一个全局事务,将其分解为若干个分支事务,而一个分支事务是一个满足 ACID 的本地事务,因此我们可以操作分布式事务像操作本地事务一样。

Seata的三种角色:
seata使用体验_第1张图片

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围,开始全局事务、提交或回滚全局事务。一般是一个方法,保证方法内的rpc调用对数据库的操作同时成功或失败。
  • RM ( Resource Manager ) - 资源管理器:管理分支事务处理的资源( Resource ),与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。可以认为一个数据库实例是一个RM

TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。

工作流程:
seata使用体验_第2张图片

  1. TM 请求 TC 开启一个全局事务。TC 会生成一个 XID 作为该全局事务的编号XID。XID会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。
  2. RM 请求 TC 将本地事务注册为全局事务的分支事务,通过全局事务的 XID 进行关联。

    • 如果rm发现当前线程包含xid,将本地事务注册到tc,关联到全局事务
  3. TM 请求 TC 告诉 XID 对应的全局事务是进行提交还是回滚。

    • 当@GlobalTransaction的方法执行完成后,判断是提交还是回滚
    • 也可调用rollback(xid)方法手动回滚
  4. TC 驱动 RM 们将 XID 对应的自己的本地事务进行提交还是回滚。

机制:
两阶段提交协议的演变:
一阶段:
解析sql,生成回滚sql,将业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。提交前向TC注册分支,提交后将本地事务提交的结果上报给 TC。
二阶段:
提交异步化,非常快速地完成。
回滚通过xid找到一阶段的回滚日志进行反向补偿。

框架支持:

  • rpc框架:Dubbo,Apache HttpClient,Spring Cloud OpenFeign,Spring RestTemplate,gRPC,SOFA-RPC,Motan
  • Seata 是基于 DataSource 数据源进行代理来拓展,所以天然对主流的 ORM 框架提供了非常好的支持:MyBatis、MyBatis-Plus、JPA、Hibernate

原理解析:

  • 如果保证某个方法内的rpc调用是一个全局事务,添加@GlobalTransaction。当方法被调用,会生成xid绑定到当前线程并将xid传递到下游服务,下游服务不可再用@GlobalTransaction注解,因为会生成新的xid,无法纳入同一全局事务。带有xid的下游服务在操作数据库时,RM会将自己的事务状态告知TC。当方法执行完成,TC根据RM报告的状态决定提交还是回滚。
  • 类似日志添加流水号,seata通过threadlocal绑定的xid管理事务,有xid的线程如果执行sql会纳入对应全局事务已经完成的xid,再执行会报错。异步线程需要传递xid,如hystrix。
  • Seata会捕获@GlobalTransaction注解的方法异常,如果捕捉到,则进行全局回滚。如果操作mysql的过程中出现异常,也会回滚。
  • 回滚前可以查到更新的数据,因此数据最终一致,可能会读到脏数据
  • 支持同步调用,异步调用无法确保主线程执行完成时,全局事务是否完成。异步调用可以用基于mq的全局事务
  • 实质是一种补偿机制,解析sql生成undo log,保证undo sql与业务sql在同一事务执行,可进行回滚,避免长事务

使用:
通过feign调用

  • 如果没有定义callback

    • 下游服务执行异常未被捕获抛掷上游,由于上游未捕捉到,异常被seata捕捉则rollback
    • 下游服务执行异常由自定义逻辑捕获

      • 没有rollback(xid),上游执行正常,不会rollback
      • 执行rollback(xid),触发rollback
  • 如果定义callback

    • 上游不会触发rollback,由下游决定

解决方案:

  • 一般上游服务都会处理callback逻辑,
  • 下游服务超时,由callback向上游响应超时,可正常commit。这时下游服务无法再写入mysql,因为全局xid已经commit。这时应该在callback处rollback(xid)
  • 下游异常,响应error,由上游的callback逻辑处理,这时服务会正常commit,而下游不会保证本地事务。下游需要添加拦截全局异常的切面,出现异常时rollback(xid)

参考:
http://seata.io/zh-cn/blog/se...
http://seata.io/zh-cn/docs/overview/what-is-seata.html
https://seata.io/zh-cn/blog/seata-at-mode-design.html
https://seata.io/zh-cn/blog/seata-xa-introduce.html
https://seata.io/zh-cn/blog/seata-at-mode-start-rm-tm.html
http://www.itsoku.com/article...
https://seata.io/zh-cn/blog/d...
https://blog.csdn.net/sinat_2...
https://www.jianshu.com/p/ea4...
https://objcoding.com/2019/07/11/seata/

你可能感兴趣的