Go微服务需聚焦边界、通信与可观测性:按业务域(非技术层)划分服务并独占数据库;HTTP调用须显式配置Client超时与重试,禁用默认客户端。

Go微服务不是把单体拆成多个main.go就完事了——90%的线上故障都源于边界、通信和可观测性这三块没对齐。
服务边界划分:别按技术层切,要按业务域切
很多团队一上来就把handler、service、dao各自打包成服务,结果调用链横跨五六跳,数据库还共用一个实例。这不是微服务,是“分布式单体”。
- 真正有效的拆分依据是领域事件和核心聚合,比如“订单创建”必须原子完成,不能拆成
order-service写订单、inventory-service扣库存再发消息 - 每个服务应独占数据库,禁止跨库JOIN或直连其他服务的PostgreSQL
- 用
go:generate配合DDD工具(如ent或gorm)生成带明确上下文边界的CRUD代码,避免手写模糊的DAO泛化层
HTTP客户端超时与重试:别用http.DefaultClient
直接用http.Get或http.DefaultClient发起调用,在Kubernetes里等于给Pod埋雷——连接卡住、响应延迟、goroutine堆积,三者叠加就是雪崩起点。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
- 必须显式构造
http.Client,设置Timeout、Transport.DialTimeout、Transport.TLSHandshakeTimeout三项 - 重试不能无脑
for i := 0; i ,要结合<code>backoff.Retry或自定义指数退避逻辑,且只对codes.Unavailable、codes.DeadlineExceeded等可重试错误生效 - 生产环境建议用
gRPC替代HTTP做内部通信,序列化开销低、流控机制原生支持,protoc生成的stub天然隔离协议细节
日志与追踪:结构化日志不等于加zap,而是带traceID贯穿请求
上线后查问题时发现:日志分散在12个Pod里,每个log line都没法关联到同一笔订单请求——说明从第一行日志起就没注入上下文。
立即学习“go语言免费学习笔记(深入)”;
- 中间件里必须从
context.Context提取trace_id,通过zap.String("trace_id", traceID)写入每条日志,不能靠日志系统后期拼接 -
OpenTelemetry的Tracer需在HTTP handler入口启动span,并用otelhttp.NewHandler包装所有路由,否则gRPC调用链会断 - 避免在goroutine里直接用
log.Printf打日志,它不继承父goroutine的context,traceID丢失且格式不统一
最常被忽略的是配置热加载和信号处理:服务重启时没优雅关闭监听socket,导致Kubernetes杀Pod前仍有请求进入;配置变更后没触发Reload,新参数压根没生效。这些点不在架构图里,但每天都在真实发生。

















