微服务通信必须规范连接管理与错误处理:grpc需复用clientconn、设超时、配tls;http客户端须自定义超时与连接池;消息消费需幂等设计并监控死信。

微服务间通信不是“能通就行”,而是必须设超时、复用连接、区分错误类型、避免泄漏——否则线上抖动或雪崩是迟早的事。
gRPC 客户端别每次调用都 grpc.Dial
反复 grpc.Dial 会触发 DNS 查询、TLS 握手、HTTP/2 协商,开销远超一次 RPC 调用本身。实测高频场景下,连接建立耗时可能占整体延迟的 60% 以上。
- 全局复用单个
*grpc.ClientConn实例,或按目标服务做连接池管理 - 使用
grpc.WithTransportCredentials(如credentials.NewTLS)而非grpc.WithInsecure,但注意 TLS 握手只在首次连接发生 - 务必配
grpc.WithTimeout或靠context.WithTimeout控制,服务端不要重设 deadline - 若用 Consul/Etcd 做服务发现,需自定义
grpc.Resolver,而不是拼接固定地址
HTTP/REST 调用不设 http.Client 就等于没设超时
Go 标准库的 http.DefaultClient 默认无超时,一旦下游卡住,goroutine 和连接全被占满,很快拖垮整个服务。
- 显式创建
*http.Client,并配置Transport:设置MaxIdleConns(建议 ≥50)、MaxIdleConnsPerHost、IdleConnTimeout(如30 * time.Second) - 所有请求必须带
context.Context,用context.WithTimeout设上限(核心链路建议 ≤2s) - 收到响应后立刻调用
resp.Body.Close(),否则连接无法归还到池中,MaxIdleConnsPerHost很快耗尽 - 错误要分层判断:
err != nil是网络层失败(如连接拒绝),resp.StatusCode >= 400是业务层返回,不能一概重试
消息队列消费端必须自己保证幂等
Kafka/RabbitMQ 只保证“至少一次”投递,网络分区、消费者重启、重平衡都会导致重复消息——框架不会替你去重。
- 用业务主键(如
order_id)+ 唯一操作标识(如event_id)做数据库唯一索引,插入失败即跳过 - 避免用时间戳或随机 UUID 做去重依据,它们无法跨实例协同
- 消费逻辑里别混写 DB 更新和发消息,否则重试时可能二次发通知
- 死信队列要配,但别只扔进去就不管;需有监控告警 + 定期人工巡检
最常被忽略的不是协议选型,而是连接生命周期管理——grpc.ClientConn 关闭时机、http.Client.Transport 的复用范围、Kafka consumer group 的 rebalance 行为,这些细节不抠清楚,压测时才暴露问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











