什么是Protocol Buffer命名空间冲突?
所有链接到Go二进制文件的Protocol Buffer声明都被插入到一个全局注册表中。
每个Protocol Buffer声明(例如,枚举、枚举值或消息)都有一个绝对名称,该名称是包名称与.proto源文件中声明的相对名称的连接(例如,my.proto.package.MyMessage.NestedMessage)。Protocol Buffer语言假设所有声明都是普遍唯一的。
如果链接到Go二进制文件的两个Protocol Buffer声明具有相同的名称,那么这将导致命名空间冲突,注册表无法通过名称正确解析该声明。根据使用的Go protobuf版本不同,这可能会在初始化时引发panic,或者静默地忽略冲突,并在运行时可能导致潜在的错误。
如何解决Protocol Buffer命名空间冲突?
解决命名空间冲突的最佳方法取决于冲突发生的原因。
常见的命名空间冲突原因有:
-
存在vendored(供应商)的.proto文件。当一个单独的.proto文件被生成为两个或更多的Go包,并且链接到同一个Go二进制文件时,会在生成的Go包中的每个Protocol Buffer声明上发生冲突。这通常发生在一个.proto文件被vendored,并且从它生成了一个Go包,或者生成的Go包本身被vendored。用户应避免vendored,而是依赖于集中化的Go包来使用该.proto文件。
-
如果一个.proto文件由外部组织拥有,并且缺少go_package选项,则应与该.proto文件的所有者协调,以指定一个集中化的Go包,所有用户都可以依赖。
-
缺失或使用过于通用的proto包名称。如果一个.proto文件没有指定包名称或使用过于通用的包名称(例如,“my_service”),那么该文件内部的声明很可能与宇宙中的其他声明发生冲突。我们建议每个.proto文件都有一个包名称,该名称是经过深思熟虑选择的,具有普遍唯一性(例如,以公司名称为前缀)。
警告: 在.proto文件上后期更改包名称可能会导致使用扩展字段或存储在google.protobuf.Any中的消息停止正常工作。
从google.golang.org/protobuf模块的v1.26.0版本开始,当启动一个Go程序时,如果链接到其中多个冲突的Protocol Buffer名称,将报告一个严重错误。虽然最好是修复冲突的源头,但可以通过以下两种方式立即解决致命错误:
- 在编译时设置。可以在编译时通过链接器初始化的变量来指定处理冲突的默认行为:
go build -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn"
- 在程序执行时设置。可以通过环境变量来设置处理冲突的行为,当执行特定的Go二进制文件时:
GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn ./main
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意