go分布式事务 mysql_分布式|事务框架 seata-golang 通信模型详解

本文详细介绍了seata-golang的TCP通信模型,包括session管理、Transaction Manager和Resource Manager的注册过程。通过OnMessage方法处理事务消息,并根据消息类型调用相应逻辑如全局事务的开始、状态查询、报告和提交/回滚。同时,文章提到了session_manager的实现,用于保存客户端与Transaction Coordinator的连接,以便进行TM和RM的注册。seata-golang支持AT模式和TCC模式,实现与java版seata的互通,并提供了高可用部署的TC端。
摘要由CSDN通过智能技术生成

func (coordinator *DefaultCoordinator) (session getty.Session, err error) {// 释放 TCP 连接SessionManager.ReleaseGettySession(session)session.Closelog.Errorf("getty_session{%s} got error{%v}, will be closed.", session.Stat, err)}

func (coordinator *DefaultCoordinator) OnClose(session getty.Session) {log.Info("getty_session{%s} is closing......", session.Stat)}

func (coordinator *DefaultCoordinator) OnMessage(session getty.Session, pkg interface{}) {log.Debugf("received message:{%v}", pkg)rpcMessage, ok := pkg.(protocal.RpcMessage)if ok {_, isRegTM := rpcMessage.Body.(protocal.RegisterTMRequest)if isRegTM {// 将 TransactionManager 信息和 TCP 连接建立映射关系coordinator.OnRegTmMessage(rpcMessage, session)return}

heartBeat, isHeartBeat := rpcMessage.Body.(protocal.HeartBeatMessage)if isHeartBeat && heartBeat == protocal.HeartBeatMessagePing {coordinator.OnCheckMessage(rpcMessage, session)return}

if rpcMessage.MessageType == protocal.MSGTYPE_RESQUEST ||rpcMessage.MessageType == protocal.MSGTYPE_RESQUEST_ONEWAY {log.Debugf("msgId:%s, body:%v", rpcMessage.Id, rpcMessage.Body)_, isRegRM := rpcMessage.Body.(protocal.RegisterRMRequest)if isRegRM {// 将 ResourceManager 信息和 TCP 连接建立映射关系coordinator.OnRegRmMessage(rpcMessage, session)} else {if SessionManager.IsRegistered(session) {defer func {if err := recover; err != nil {log.Errorf("Catch Exception while do RPC, request: %v,err: %w", rpcMessage, err)}}// 处理事务消息,全局事务注册、分支事务注册、分支事务提交、全局事务回滚等coordinator.OnTrxMessage(rpcMessage, session)} else {session.Closelog.Infof("close a unhandled connection! [%v]", session)}}} else {resp, loaded := coordinator.futures.Load(rpcMessage.Id)if loaded {response := resp.(*getty2.MessageFuture)response.Response = rpcMessage.Bodyresponse.Done

func (coordinator *DefaultCoordinator) OnCron(session getty.Session) {

}

coordinator.OnRegTmMessage(rpcMessage, session)注册 Transaction Manager, coordinator.OnRegRmMessage(rpcMessage, session)注册 Resource Manager。具体逻辑分析见下文。

消息进入coordinator.OnTrxMessage(rpcMessage, session)方法,将按照消息的类型码路由到具体的逻辑当中:

switch msg.GetTypeCode {case protocal.TypeGlobalBegin:req := msg.(protocal.GlobalBeginRequest)resp := coordinator.doGlobalBegin(req, ctx)return respcase protocal.TypeGlobalStatus:req := msg.(protocal.GlobalStatusRequest)resp := coordinator.doGlobalStatus(req, ctx)return respcase protocal.TypeGlobalReport:req := msg.(protocal.GlobalReportRequest)resp := coordinator.doGlobalReport(req, ctx)return respcase protocal.TypeGlobalCommit:req := msg.(protocal.GlobalCommitRequest)resp := coordinator.doGlobalCommit(req, ctx)return respcase protocal.TypeGlobalRollback:req := msg.(protocal.GlobalRollbackRequest)resp := coordinator.doGlobalRollback(req, ctx)return respcase protocal.TypeBranchRegister:req := msg.(protocal.BranchRegisterRequest)resp := coordinator.doBranchRegister(req, ctx)return respcase protocal.TypeBranchStatusReport:req := msg.(protocal.BranchReportRequest)resp := coordinator.doBranchReport(req, ctx)return respdefault:return nil}

4)session manager 分析

Client 端同 Transaction Coordinator 建立连接起连接后,通过 clientSessionManager.RegisterGettySession(session)将连接保存在 serverSessions = sync.Map{}这个 map 中。map 的 key 为从 session 中获取的 RemoteAddress 即 Transaction Coordinator 的地址,value 为 session。这样,Client 端就可以通过 map 中的一个 session 来向 Transaction Coordinator 注册 Transaction Manager 和 Resource Manager 了。具体代码见getty_client_session_manager.go 。

Transaction Manager 和 Resource Manager 注册到 Transaction Coordinator 后,一个连接既有可能用来发送 TM 消息也有可能用来发送 RM 消息。我们通过 RpcContext 来标识一个连接信息:

type RpcContext struct {Version stringTransactionServiceGroup stringClientRole meta.TransactionRoleApplicationId stringClientId stringResourceSets *model.SetSession getty.Session}

当收到事务消息时,我们需要构造这样一个 RpcContext 供后续事务处理逻辑使用。所以,我们会构造下列 map 来缓存映射关系:

var (// session -> transactionRole// TM will register before RM, if a session is not the TM registered,// it will be the RM registeredsession_transactionroles = sync.Map{}// session -> applicationIdidentified_sessions = sync.Map{}

// applicationId -> ip -> port -> sessionclient_sessions = sync.Map{}

// applicationId -> resourceIdsclient_resources = sync.Map{})

这样,Transaction Manager 和 Resource Manager 分别通过coordinator.OnRegTmMessage(rpcMessage, session)和 coordinator.OnRegRmMessage(rpcMessage, session)注册到 Transaction Coordinator 时,会在上述 client_sessions map 中缓存 applicationId、ip、port 与 session 的关系,在client_resources map 中缓存 applicationId 与 resourceIds(一个应用可能存在多个 Resource Manager) 的关系。

在需要时,我们就可以通过上述映射关系构造一个 RpcContext。这部分的实现和 java 版 seata 有很大的不同,感兴趣的可以深入了解一下。具体代码见getty_session_manager.go 。

至此,我们就分析完了seata-golang 整个 RPC 通信模型的机制。

seata-golang 的未来

seata-golang 从今年 4 月份开始开发,到 8 月份基本实现和 java 版seata 1.2 协议的互通,对 mysql 数据库实现了 AT 模式(自动协调分布式事务的提交回滚),实现了 TCC 模式,TC 端使用 mysql 存储数据,使 TC 变成一个无状态应用支持高可用部署。下图展示了 AT 模式的原理:

852ba4ca091d04dc1d00af6b1ee0d692.pngseata 官方 : https://seata.io

java 版 seata : https://github.com/seata/seata

seata-golang 项目地址 : https://github.com/opentrx/seata-golang

seata-golang go 夜读 b 站分享: https://www.bilibili.com/video/BV1oz411e72T

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值