0%

基于protobuf的定义在跨语言消息传递中的应用

背景

在需要消息队列的场景中,生产端和消费端会事先就消息体格式达成共识确保生产端发送的消息在消费端能正常识别;如果生产端和消费都是Java项目,我们通常会定义消息体的Jar,让生产端和消费端都引用Jar确保消息的一致性;但在跨语言消息传递中通常通过文档约定消息格式各自定义自己的消息体。在我们实际使用过程中发现不同语言之间传递信息还是会出现一些问题;比如:Java用fastjson输出复杂数据在Go项目解析失败,而且各语言在配置mq参数时候有各自的约定,人工操作容易引起误操作,所以我们希望能有一套跨语言的工具能分别生出各自语言的代码和配置。

思路

现有系统跨语言之间RPC的调用我们采用了gRPC,很自然的想到可以借鉴gRPC Protobuf定义消息体。具体方法就是扩展google.protobuf.MethodOptions定义

方法

下面以RabbitMQ为例,在Protobuf文件中定义MQ相关参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

extend google.protobuf.MethodOptions {

// exchange类型: topic direct fanout ,默认: direct
string routeType = 7010101;

// producer 发送到exchange上有效的routekey; 仅topic模式有效
repeated string routeKey = 7010102;

//consumer监听的队列名称,direct模式 该参数无效
repeated string listener = 7010103;

// 延迟队列的延迟时间
int32 delay = 6010106;
}

说明: 如果exchange为topic模式,监听队列绑定的routekey必须根据此处定义的routKey定义设置;比如文件定义的routeKey是a.b.c则consumer端绑定到队列的routkey只能是 a.b.c, a.b., a., * 其中之一

生产Java代码

通常在Maven工程中我们使用protobuf-maven-plugin插件生成gRPC的Java代码。现在我们可以扩展protobuf-maven-plugin插件生成MQ的代码。核心扩展点如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
 @Mojo(
name = "compile-mq",
defaultPhase = LifecyclePhase.GENERATE_SOURCES,
requiresDependencyResolution = ResolutionScope.COMPILE,
threadSafe = true
)
public class ProtocCompileMQMojo extends AbstractProtocCompileMojo{
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
super.execute();
// 利用 DescriptorProtos.FileDescriptorSet 读取proto文件的定义根据规范生出Java文件
}
}

最后配合MQ的SDK可以大大提高开发效率而且减低配置的复杂性。