微服务模块划分的本质是按端到端业务能力而非技术分层切分,真正独立的服务需满足三硬指标:专属数据库表、独立API路由前缀、可单独上线回滚;否则只是逻辑模块而非服务。

模块划分不合理,本质是把单体思维套在微服务壳子里——不是目录分得多,而是业务边界没划清。
按业务能力而非技术层切模块
常见错误是建 user-api、user-service、user-repo 三个子目录,还各自配 go.mod。这看起来“模块化”,实则仍是单体:它们共用同一份数据库连接、共享内部结构体、上线必须一起发版。
真正该做的,是识别端到端业务能力。比如:
-
auth模块只管登录态签发与校验,不存用户资料,也不处理头像上传 -
profile模块只管展示型字段(昵称、头像、性别),不碰密码或 token -
address模块只做第三方地址清洗,不参与下单流程
每个模块对应一个独立 go.mod,module path 如 github.com/org/project/auth,且能单独 go build -o auth ./cmd/auth 构建。
立即学习“go语言免费学习笔记(深入)”;
判断模块是否可独立部署的三个硬指标
别信目录名,拿这三条现场验证:
- 有没有自己专属的数据库表?不能和
payment共用一张users表 - 有没有独立的 API 路由前缀?比如
/auth/v1/和/profile/v1/不混在一起 - 上线/回滚时能不能不牵连其他模块?改
auth的 JWT 签名算法,profile不用重启
如果任一条件不满足,就还不是服务,只是逻辑模块——先抽 interface 解耦,再物理拆分。
proto 文件和公共类型怎么放才不踩坑
proto 不是共享工具,是契约。放错位置,比 DB 连不上还难排查。
- 所有
.proto必须放在统一路径,如api/auth/v1/auth.proto,禁止散落在各模块的internal/下 - 字段变更只允许追加、设为
optional或用reserved重命名;删字段或改类型 = 强制全链路升级 - 包名必须带版本,如
package authpbv2;,而不是靠 URL 路径区分 - 禁止定义聚合 RPC,比如
rpc GetUserWithOrders()——组合逻辑应由调用方完成,不是契约责任
DTO 不该放在公共 pkg/ 下,而应由调用方按需定义,或通过 proto 生成后直接使用。
多 module 工程里如何管理依赖和本地开发
根目录下 go.mod 可有可无,关键是子模块间不能直接 import 对方的 internal/ 包。
- 跨模块调用必须走 interface + DI(如 wire 注入),或走 gRPC/HTTP client
- 本地开发时用
replace指向本地路径,例如:replace github.com/org/project/auth => ../auth - 测试时注入 mock 实现,不要让
auth.Service直接 newpayment.Client - 构建时精确指定目标:
go build -o payment ./cmd/payment,避免误打包无关模块
最易被忽略的是连接池隔离:每个模块的 *sql.DB、redis.Client 必须在本模块内初始化和关闭,不能复用全局实例——否则一个模块抖动,全链路雪崩。


















