微服务应按业务能力而非模块拆分,每个服务需独立数据库、明确边界、结构化日志、grpc通信、注册中心管理及全链路可观测性。

服务拆分不能按“模块”切,得按业务能力划限界上下文
很多人一上来就建 userservice、orderservice,结果所有逻辑全塞进去——密码重置、地址校验、优惠券发放全在同一个服务里跑,数据库共用一张 users 表,这根本不是微服务,是单体披了层 HTTP 外衣。
真正该做的是识别「谁在什么场景下完成什么完整业务动作」:比如「用户登录」和「用户头像上传」压根不共享数据生命周期,也不共用一致性边界,就必须拆成两个服务:authn(只管 token 签发/校验)和 profile(只管头像、昵称、偏好)。每个服务配独立数据库 schema,甚至独立 PostgreSQL 实例。
- 别用
github.com/yourorg/backend/users这种路径,改用github.com/yourorg/authn、github.com/yourorg/profile - 每个服务的
internal/目录只对本服务可见,禁止跨服务 importinternal/xxx - 接口定义统一放在
api/下,用.proto文件约束契约,而不是靠文档或口头约定
服务间通信首选 gRPC,HTTP 只留作对外网关入口
用 net/http + JSON 写内部服务调用,三个月后你一定会遇到三类问题:前端传来的 user_id 是 string,后端解析成 float64;错误码全挤在 HTTP 状态码里,404 到底是资源不存在,还是下游超时?没有默认连接池,每次都要手写 &http.Client{Transport: ...}。
gRPC 不是“为了高大上”,而是解决这些实际痛点的最小可行方案:字段类型编译期校验、status.Code(err) 直接区分 CodeNotFound 和 CodeDeadlineExceeded、grpc.DialContext 默认带连接复用和健康探测。
- 对外暴露 REST 接口?用
grpc-gateway自动生成反向代理,不用维护两套逻辑 - 客户端初始化必须加超时:
ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond),否则一个卡死的下游会拖垮整条链路 - 别手动拼
http://service-name:8080,用grpc.WithResolvers配合 Consul 或 etcd 的 resolver,让 DNS 式服务发现生效
可观测性不是上线后再补,而是一启动就埋点
没日志、没指标、没 trace ID 的微服务,等于把系统扔进黑盒。等出问题再加 log.Printf 和 prometheus.NewCounter?这时候连哪个服务挂了都得靠 curl 猜。
Go 生态有足够轻量的组合:用 zerolog 输出结构化 JSON 日志(字段含 service、trace_id、span_id),用 prometheus/client_golang 暴露 /metrics,用 go.opentelemetry.io/otel 在 HTTP 和 gRPC 中间件里自动透传 context。
- 每条日志必须带
trace_id,且从第一个入口(如 API 网关)开始注入,不能在每个服务里重新生成 -
http_request_duration_seconds和grpc_server_handled_total这类基础指标,要在第一个main.go就注册,而不是等“后面再统一加” - 拒绝
fmt.Printf和裸log.Println,它们无法被结构化解析,也带不了上下文字段
服务注册与配置管理,别自己手写心跳和环境变量解析
用 os.Getenv("SERVICE_ADDR") 启动服务?那扩容到 10 个实例时,你得改 10 份配置;写个 for 循环每 5 秒 ping 一次下游健康状态?不如直接用注册中心内置的 TCP 或 HTTP 健康检查。
Consul、etcd、Nacos 都提供开箱即用的服务注册+健康探活机制,Go 侧只需在启动时调一次注册 API,关机前 deregister 即可。配置则交给 spf13/viper,它支持从环境变量、YAML 文件、etcd 多源加载,且能监听变更热更新。
- 注册逻辑别写在
main()里,抽成pkg/registry下的RegisterWithConsul(),方便单元测试 mock - 敏感配置(如数据库密码)绝不能放 YAML,走 Kubernetes
Secret或 Consul KV 的 ACL 保护路径 - 别依赖 “服务启动后自动发现其他服务”,先确保本服务能被发现,再谈调用别人
最容易被忽略的其实是服务生命周期的对齐:注册成功前不接受流量,健康检查失败时主动 deregister,进程退出前等待所有 gRPC 连接 graceful shutdown。这些细节不写进代码,光靠运维喊话是没用的。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











