刚刚学习了 go-zero框架,已经学会了在同一个项目里 api 调用 rpc服务,但是如果是在不同的项目呢。有没有老师能答疑解惑
我刚刚在网上查到的是直接复制 rpc代码到 api项目目录中,请问正常工作中是这样处理吗
理论上,这种方法确实可以实现 API 项目调用 RPC 服务。因为 API 项目需要知道 RPC 服务提供的接口(方法、请求/响应结构体),而这些信息通常是从 RPC 项目的 .proto 文件生成的 Go 代码中获得的。将这部分生成的代码复制过来,API 项目就能编译通过并调用。
但这在正常的实际工作中是推荐的做法吗?
答案是:不推荐。
这种做法的主要问题在于:
代码冗余和重复 (Code Duplication): RPC 项目和 API 项目都拥有同一份描述 RPC 接口的代码副本。
维护困难 (Maintenance Hell): 如果 RPC 服务的接口发生变化(比如添加一个新方法、修改一个结构体),你需要:
在 RPC 项目中更新 .proto 文件。
重新生成 RPC 项目的服务端代码。
手动地将新的、从更新后的 .proto 文件生成的客户端代码复制到每一个调用这个 RPC 服务的 API 或其他项目中。
如果漏掉任何一个地方,或者复制的版本不一致,就会导致编译错误或运行时错误。这在微服务数量多起来之后,会变得极其难以管理和维护。
版本控制问题: 很难清晰地追踪各个 API 项目到底使用了哪个版本的 RPC 接口代码。
正常工作中的标准处理方式:使用 Go Module 和共享仓库
在微服务架构中,当多个服务需要共享同一份接口定义(比如 RPC 的 .proto 文件和生成的客户端代码)时,标准的做法是将这些共享的代码放在一个独立的 Go Module 中,通常是一个单独的代码仓库。
具体的步骤大致如下:
创建共享仓库/Module: 新建一个 Git 仓库,例如命名为 my-org/proto (my-org 是你的组织或用户名)。这个仓库将作为一个独立的 Go Module。
存放 .proto 文件: 将你的 RPC 服务定义 .proto 文件放在这个共享仓库中,按照规范组织目录结构,例如 my-org/proto/user/user.proto。
生成共享代码: 在这个共享仓库中,使用 goctl 或 protoc 工具,根据 .proto 文件生成 Go 代码。注意: 只生成客户端需要的接口定义和桩代码。例如,可以使用 goctl protoc 命令,指定输出目录到这个共享仓库的某个位置。
版本化共享 Module: 使用 Git Tag 来标记这个共享 Module 的版本(例如 v1.0.0)。
RPC 服务端项目依赖共享 Module: 在你的 RPC 服务项目 (my-org/user-rpc) 的 go.mod 文件中,添加对 my-org/proto 这个 Module 的依赖,指定版本号(例如 require my-org/proto v1.0.0)。RPC 服务端代码在实现时会导入并使用这个共享 Module 中生成的接口定义。
API 网关项目依赖共享 Module: 在你的 API 网关项目 (my-org/api-gateway) 的 go.mod 文件中,也添加对 my-org/proto 这个 Module 的依赖,指定相同的版本号(例如 require my-org/proto v1.0.0)。API 项目会导入并使用这个共享 Module 中生成的客户端代码来发起 RPC 调用。
更新流程: 当 RPC 接口发生变化时,更新共享仓库中的 .proto 文件,重新生成代码,提交并推送到共享仓库,然后打上新的版本 Tag(例如 v1.1.0)。接着,在依赖这个共享 Module 的所有项目(包括 RPC 服务端项目自身如果需要同步更新的话,以及所有客户端项目如 API 网关)中,修改 go.mod 文件,将依赖版本更新到新的 Tag (v1.1.0),然后运行 go mod tidy。
优点:
单一事实来源: RPC 接口定义和相关的客户端代码只在一个地方维护。
易于版本管理: 可以清晰地知道每个项目依赖的是哪个版本的 RPC 接口。
减少冗余: 避免了在多个项目中复制粘贴相同的代码。
提高协作效率: 当接口变化时,只需要通知相关项目的开发者更新其 go.mod 依赖即可。
基于porto文件啊