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发来的消息,完成分布式事务的所有流程。

相关推荐
程序员cxuan4 小时前
Loop 还没玩明白,Graph Engineering 又火了。
人工智能·后端·程序员
uzong4 小时前
把一面面试总结做成一个 Skill:重复的事,就别每次都重写
后端·面试
程序员海军5 小时前
一个 AI 应用开发程序员的一天,都在屏幕前忙些什么?
前端·后端·程序员
不能放弃治疗5 小时前
MCP
后端
江湖十年6 小时前
Go 语言中 YAML to JSON 踩坑笔记
后端·go·json
你驴我7 小时前
WhatsApp 消息撤回与编辑的幂等性设计实践
java·服务器·前端·后端·python
一缕清烟在人间7 小时前
HarmonyOS开发实战:小分享-TextEditPage文字编辑器——Header+TextArea+工具栏
后端·华为·harmonyos·鸿蒙
人间凡尔赛7 小时前
K8s 十年之变:从 Cloud Native 到 AI Native,2026 年后端架构的范式革命
后端·云原生·架构
程序员cxuan7 小时前
Opus 5 深夜炸场,价格还挺香。。。
人工智能·后端·程序员
北冥you鱼7 小时前
Go 语言新手扫盲:指针 * 和 & 使用场景详解
开发语言·后端·golang