go构建高并发微服务的核心是用对goroutine、选准通信协议、分清职责边界、控制好上下文生命周期;net/http默认并发模型已足够支撑10k+连接,应避免误用go func()导致泄漏,内部通信优先grpc,对外暴露用rest/json。

直接上结论:Go 构建高并发微服务,核心不是堆框架,而是用对 goroutine、选准通信协议、分清职责边界、控制好上下文生命周期——其余都是围绕这四点的工程取舍。
为什么 net/http + goroutine 就能扛住万级并发
很多人一上来就装 Gin、Echo 或 go-zero,但标准库 net/http 默认就支持并发处理每个请求启动一个 goroutine。它的底层是基于 epoll/kqueue 的非阻塞 I/O,配合 Go 运行时调度器,单机轻松支撑 10k+ 活跃连接。
常见误区是手动在 handler 里起 go func() {...}(),这反而容易失控。正确做法是:
- 信任
http.Server的默认并发模型,不额外包裹 goroutine - 在业务逻辑中,仅对真正可并行、无状态、耗时操作(如调用下游 API、批量写日志)才显式起
goroutine - 所有 goroutine 必须绑定
context.Context,并在超时或取消时主动退出,避免泄漏 - 用
sync.WaitGroup或errgroup.Group管理子任务集合,别靠time.Sleep等协程结束
gRPC 和 REST 怎么选:看调用方和场景
内部服务间通信,优先选 gRPC;对外暴露 API,用 REST/JSON。这不是性能洁癖,而是契约成本问题。
gRPC 的优势在真实压测中才明显:
- 同量级数据传输,
gRPC比 JSON 小 30%~50%,HTTP/2 多路复用减少连接数 - proto 定义强制接口收敛,字段变更需兼容升级,避免 “改个字段前端炸一片”
- 流式接口(
server-streaming)天然适合推送类场景,比如订单状态变更通知
但代价是:调试困难(不能直接 curl)、客户端生成代码侵入强、跨语言需维护多份 proto。如果只是两个 Go 服务互调,且 QPS net/http + json.RawMessage 也完全够用。
服务注册与发现不能“手写轮子”
别用全局 map 存 IP 列表,也别靠配置文件 reload。生产环境必须集成真实注册中心。
选型建议很明确:
- 已在用 Kubernetes:直接走
ServiceDNS,不用额外注册——order-service.default.svc.cluster.local:8080就是服务名 - 需要跨集群或混合云:选
etcd(K8s 原生,强一致)或Consul(健康检查更灵活,带 UI) - 不要用 ZooKeeper:Go 生态支持弱,client 库陈旧,运维成本高
关键动作只有两步:服务启动时注册(带 TTL) + 退出前反注册。注册内容至少包含:服务名、IP、端口、健康检查路径(如 /health)。任何没做反注册的服务下线,都会让其他服务持续发请求过去。
go-zero 不是银弹,但能省掉 70% 模板代码
go-zero 的价值不在“高性能”,而在它把微服务高频需求固化成约定:配置加载、中间件链、限流熔断、JWT 验证、CRUD 代码生成——全部由 goctl 一条命令产出。
但它有硬约束:
- 必须用
.api文件定义路由,不能自由写router.GET - 业务逻辑必须塞进
logic层,不能直接在handler里写 SQL - 配置结构被
zrpc或rest框架锁定,想换 Consul 为 Nacos 得改源码
如果你团队刚起步、服务数量 go-zero 是最快上线的选择;但如果已有统一配置中心或链路追踪体系,强行套用反而要削足适履。
最常被忽略的点是:高并发不是压出来的,是收出来的——限制数据库连接数、限制 HTTP client 超时、限制 goroutine 并发池大小、限制日志采样率。没做这些限制的“高并发服务”,上线后第一个流量高峰就会把自己拖垮。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











