Go micro集成DTM分布式事务的方法

背景

我有一个go micro开发的微服务要引入分布式事务,用的是Saga模式,结果遇到DTM访问gRPC接口报错,返回Unsupported Content-Type: application/grpc+dtm_raw,网上搜了一圈没有任何资料,AI也给不出答案,分布式事务是必不可少的,很明显框架默认不支持DTM但还是要解决。

分析

我们可以通过错误分析得知是不支持application/grpc+dtm_raw这种格式,因为go micro的GRPC Server有个newGRPCCodec方法,源码如下:

go 复制代码
func (g *grpcServer) newGRPCCodec(contentType string) (encoding.Codec, error) {
	codecs := make(map[string]encoding.Codec)
	if g.opts.Context != nil {
		if v, ok := g.opts.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && v != nil {
			codecs = v
		}
	}
	if c, ok := codecs[contentType]; ok {
		return c, nil
	}
	if c, ok := defaultGRPCCodecs[contentType]; ok {
		return c, nil
	}
	return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
}

Content-Type对应的Codec来实现,先检查Context里面有没有对应的编解码器,如果没有就从defaultGRPCCodecs选择一个来解码,还是找不到就报上文提到的错误。这个格式是DTM特有的,defaultGRPCCodecs找不到没有相应的编解码器所以会报错,默认编解码器映射表源码如下:

go 复制代码
	defaultGRPCCodecs = map[string]encoding.Codec{
		"application/json":         jsonCodec{},
		"application/proto":        protoCodec{},
		"application/protobuf":     protoCodec{},
		"application/octet-stream": protoCodec{},
		"application/grpc":         protoCodec{},
		"application/grpc+json":    jsonCodec{},
		"application/grpc+proto":   protoCodec{},
		"application/grpc+bytes":   bytesCodec{},
	}

解决方法

由于采用的是GRPC通信,application/grpc+dtm_raw和application/grpc是相通的,所以我们找到protoCodec{}结构体把它的所有方法复制出来放到自己的项目目录下,修改该编解码器的结构体名称,Name方法改成其他名字比如"grpc+dtm_raw",然后在创建GRPC Server的时候注入自定义编解码器,部分代码如下:(重点看grpcserver.Codec)这一行。

go 复制代码
import (
	grpcserver "github.com/go-micro/plugins/v4/server/grpc"
	"github.com/go-micro/plugins/v4/transport/grpc"
	"go-micro.dev/v4"
	"go-micro.dev/v4/server"
	"time"
)

func newServer(conf *config.SysConfig) micro.Option {
	// 注册到Consul
	consulRegistry := infrastructure.ConsulRegister(conf.Consul)
	return micro.Server(
		grpcserver.NewServer(
			server.Name(conf.Service.Name),
			server.Version(conf.Service.Version),
			server.Address(conf.Service.Listen),
			server.Transport(grpc.NewTransport()),
			server.Registry(consulRegistry),
			server.RegisterTTL(time.Duration(conf.Consul.RegisterTtl)*time.Second),
			server.RegisterInterval(time.Duration(conf.Consul.RegisterInterval)*time.Second),
			grpcserver.Codec("application/grpc+dtm_raw", codec.NewDtmCodec()),  // 在这里注入你的Codec,这样框架底层会先从Context里取出这个编解码器来解析DTM发出的消息格式
			grpcserver.MaxConn(conf.Service.MaxConn),
			grpcserver.MaxMsgSize(conf.Service.MaxMsgSize),
		))
}

这样我们就可以在DTM里使用自定义的编解码器正常解析DTM发来的消息,完成分布式事务的所有流程。

相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码2 天前
别再前后端各写一套表单校验了
java·后端
大勇前进2 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu2 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile2 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白802 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙2 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发2 天前
软件工程SOLID 五大设计原则
后端·软件工程