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

相关推荐
神奇小汤圆几秒前
面试官:你们项目里的线程池是怎么用的?怎么管理的?
后端
网易云信9 分钟前
网易智企IM Web体验馆:一站式在线体验即时通讯
人工智能·后端·aigc
shengjk112 分钟前
从 ASCII 到 UTF-8:一部字符集的发展史
后端
卷无止境26 分钟前
C++ 中的 `constexpr` 函数:让计算"提前"发生
后端
程序员小假1 小时前
从问题到答案:RAG系统完整处理流程与核心机制深度拆解
后端·面试·agent
喵个咪2 小时前
Go Wind UBA 拆解系列 - 架构总览:三服务、数据流与契约优先
大数据·后端·go
喵个咪2 小时前
Go Wind UBA 拆解系列 - 多租户与安全:两套隔离机制的边界
大数据·后端·go
喵个咪2 小时前
Go Wind UBA 拆解系列 - OLAP 与 SQL 硬核:25 个分析模型怎么落地
大数据·后端·go
喵个咪2 小时前
Go Wind UBA 拆解系列 - SDK 与采集层:从浏览器到 Kafka
大数据·后端·go
掘金一周2 小时前
对车完全小白,不知买油买电还是买混动,求建议| 沸点周刊 7.2
前端·人工智能·后端