我正在使用微服务架构创建系统。有两种微服务A
和B
,它们分别位于各自的存储库中。
有一个user.proto
文件,其中包含protobuf定义和gRPC方法签名。 A
使用生成的user.pb.go
作为服务器。 B
使用user.pb.go
作为A
的客户端。
一种结构化方法是在A
中出现原型定义,其中B
与A
具有代码依赖性:
A
├── pb
│ ├── user.proto
│ └── user.pb.go
└── service.go
B
└── service.go
B-->A
另一种方法是拥有另一个包含原型定义的仓库P
,其中A
和B
取决于新仓库:
A
└── service.go
B
└── service.go
P
├── user.proto
└── user.pb.go
A-->P
B-->P
或者新的仓库只能包含原始文件,并且在A和B中都生成了代码:
A
├── service.go
└── pb
└── user.pb.go
B
├── service.go
└── pb
└── user.pb.go
P
└── user.proto
这里有什么更好的方法?
答案 0 :(得分:0)
第二种方法更好。
为什么?因为添加服务C时,它自然会与A&B内联掉线。无需为任何现有组件更改导入路径代码。
是的,第三种方法可以主张这一点,但是它在每个微服务之间复制了生成的user.pb.go
。最好进行合并以避免重复。
您还可以在仓库的最高级别(即A和B级别)使用go的internal packages功能。将P
重命名为internal
可确保A
,B
(或C
等)可以使用此子包,但不会邀请其他第三方包引用此“内部”程序包。
答案 1 :(得分:0)
我认为正确的答案取决于您的项目规模。
对于小型项目或可能在团队之外使用的项目(例如,SDK附带的开源或专有产品提供给其他团队),我更喜欢第一种方法。如果您没有在主存储库中提供生成的代码(pb.go
文件),那么您的用户将不会满意,因为protoc
远非一个用户友好的工具。
作为第一种选择的变体,我回顾了所有微服务都具有单个存储库的项目(所谓的“ monorepo”)。他们将生成的pb.go
文件直接放入vendor
存储库中。
对于具有丰富的微服务后端的大型Web服务,第二个将是更好的选择。您将获得一个具有完整API定义的存储库。这将改善API的一致性,并帮助您设置发布周期。您可能会或可能不会将pb.go
与proto
文件一起放置,这取决于您的需要,但是我们通常会don't。
答案 2 :(得分:0)
如果您的团队不喜欢monorepo,我认为第三个选择是最合适的。 1个原始文件的仓库。然后,它可以作为git子模块包含在A和B中(如果您使用的是git)。 A和B可以拥有自己的协议脚本,生成的protobuf文件取决于他们使用的编程语言。