微服务拆分应基于限界上下文实现数据自治与独立演进,而非按模块命名;须以 protobuf 契约先行、禁止直连数据库、落实超时/健康检查/可观测性,并确保配置外置与日志链路追踪。

微服务拆分不是为了“有多个服务”,而是为了让每个服务能独立演进、独立发布、独立扩缩容。做不到这点,就是分布式单体。
按限界上下文(Bounded Context)而非模块名拆分
很多人一上来就建 user-service、order-service,结果半年后发现登录要查风控等级、实名状态、消息开关——四个字段来自四个不同业务规则,全塞进一个服务里,接口越加越多,数据库 schema 被迫开放,最终变成“RPC 单体”。
- 真正该问的是:谁对“用户”这个概念拥有数据主权?是注册流程决定 ID 生成规则,还是会员系统决定等级升降逻辑?
- 一个需求变更是否只改一个服务?比如“增加手机号一键登录”要不要同时动
auth-service、user-service、sms-gateway?如果要,边界就错了 - 优惠券在发券、核销、风控中语义完全不同,强行塞进一个
coupon-service,必然妥协接口、共享数据库、绕过领域规则
gRPC + proto 契约先行,禁止跨服务直连数据库
Go 没有接口继承机制,但 protobuf + grpc-go 正好补上契约约束。所有跨服务通信必须通过 .proto 定义,而不是靠“我们都知道 user 表结构”这种默契。
-
.proto文件必须由服务提供方定义,统一放在api/user/v1/user.proto这类路径下,不能散落在各服务的internal目录里 - 禁止在
order-service中直接import user-service/internal/repository或拼 SQL 查user表——这等于把耦合写死在编译期 - 接口只暴露本上下文能且只应提供的能力:
GetUser返回User,别带repeated Order;订单归属由调用方自己查order-service - 字段增删必须向后兼容:
reserved 3;标记废弃字段,并在注释写明迁移计划和时间点
服务治理从三个痛点起步:超时、健康检查、可观测性
别一上来就上 Service Mesh。Golang 微服务上线即“黑盒”的常见原因,就卡在这三件事没做实。
- 超时控制必须设在 client 端:
context.WithTimeout是唯一可靠手段;http.Client.Timeout在长连接复用下可能失效 - 健康检查不能只返回
200:/health必须探测 DB 连接、下游依赖、本地缓存状态,否则 K8s 滚动更新会把故障实例当健康节点切进来 - 日志必须带
trace_id:用zap+opentelemetry-go注入上下文,否则一次请求跨 5 个服务,根本串不起链路 - 配置不能硬编码:用
viper加载 YAML/Consul/K8s ConfigMap,环境切换不改代码、不重编译
最容易被忽略的其实是“数据自治”:每个服务的 go.mod 里不该出现其他服务的数据库驱动依赖;repository 层只对接本服务私有 DB;对外只暴露 GetUserByID(ctx, id) 这类能力接口。边界一旦模糊,治理成本就会指数级上升。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











