1.4 技术选型表:Go 框架与云组件对齐
边界划好、成本算清,接下来就是选型。创业团队选型的核心矛盾是:既要 fast,又怕被小众框架绑架。我们的选型原则只有三条——团队里至少有一个人用过、官方文档完整能查到排障指南、社区活跃且两年内不会消失。这一节给出我们最终的选型对照表,以及每一条选择背后的取舍。
Go 通信框架:从 HTTP 到 gRPC
服务间通信是第一个要拍板的。候选有三个:裸 net/http 加 JSON、gin 加 JSON、gRPC 加 protobuf。我们最后选了 gRPC 做服务间通信,同时保留一个 gin 层做对外的 HTTP 接口(小程序和老后台的存量调用)。
选 gRPC 的直接原因是性能和契约:protobuf 二进制序列化比 JSON 快两到三倍,更重要的是 proto 文件本身就是契约文档,谁改接口谁改 proto,CI 里跑一下编译就知道消费方有没有炸。
proto 定义长这样,所有跨域接口必须先评审 proto 再写实现:
syntax = "proto3";
package order;
service Order {
// 创建订单:商品域提供快照价,用户域提供等级折扣
rpc CreateOrder(CreateOrderReq) returns (CreateOrderResp);
}
message CreateOrderReq {
string user_id = 1;
repeated OrderItem items = 2; // 下单瞬间冻结的库存明细
}
| 候选方案 | 开发效率 | 性能 | 契约约束 | 我们的结论 |
|---|---|---|---|---|
| net/http + JSON | 高 | 低 | 无 | 只适合内部临时接口 |
| gin + JSON | 高 | 中 | 无 | 用作对外 HTTP 网关层 |
| gRPC + protobuf | 中 | 高 | 强制 proto | 服务间通信最终选择 |
| kratos 等全家桶 | 中 | 中 | 强 | 团队没人熟,放弃 |
没选 kratos 这类微服务全家桶框架,纯粹是人手问题:五个人没人有 kratos 生产经验,引入全家桶意味着先花两周学框架。标准库底座加 grpc-go 足够覆盖我们九成的场景,等团队有余力再考虑。
全家桶框架还有一个隐性代价:升级。框架自身的破坏性版本变更往往会裹挟业务代码跟着强行迁移,对五人团队是致命的时间黑洞。相反裸 grpc-go 的升级频率低,且每次只动通信这一层。
底层框架:每服务一个 main
每个服务的骨架非常标准:grpc server 跑业务,http server 暴露健康检查和 pprof:
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("listen failed: %v", err)
}
s := grpc.NewServer(
grpc.UnaryInterceptor(recoverInterceptor), // 兜底 panic
)
pb.RegisterOrderServer(s, &order.Server{})
go serveHTTP() // /healthz、/debug/pprof
log.Println("order service on :50051")
if err := s.Serve(lis); err != nil {
log.Fatalf("serve failed: %v", err)
}
}
go.mod 的依赖刻意保持少,三个服务的依赖合起来不到 20 个 package。少一个依赖就少一次连锁升级的痛苦。核心几行长这样:
module shop/order
go 1.21
require (
github.com/grpc/grpc-go v1.62.0 // 固定到上一个 minor
google.golang.org/protobuf v1.33.0
github.com/redis/go-redis/v9 v9.5.0
go.uber.org/zap v1.27.0 // 日志库,后面接 CLS
)
云组件对齐:五件套
云组件的选择相对省心,因为要解决的问题很明确,选型问题最终落到五件套对应关系上:
| 需求场景 | 腾讯云组件 | 替代自建方案 | 不自建的理由 |
|---|---|---|---|
| 服务运行 | 云服务器 CVM | 自建机房 | 五人团队没有运维硬件人力 |
| 削峰解耦 | 消息队列 RocketMQ | 自建 Kafka | Kafka 运维成本高 |
| 统一日志 | 日志服务 CLS | ELK | ELK 每月机器费更高 |
| 监控告警 | 云监控 | Prometheus | 已有 CVM 内置指标 |
| 对外入口 | API 网关 | nginx 自研 | 限流鉴权开箱即用 |
这套组合的核心思路是:业务团队只写业务代码,所有“管道”类的能力能买就买。自建 Kafka 或 ELK 的隐性成本不是机器费,是那一个会修它的工程师的青春。团队里没有专职运维,这条约束决定了所有选型。
五件套之间还有一个隐性收益:账号体系、计费、权限、监控大盘天然打通。CVM 的机器指标直接进云监控,触发告警后能联动策略;CLS 的日志可以在云监控里配关键词告警;API 网关的访问日志也能落到同一个 CLS 主题。如果自建这些组件,每一项都要单独搭监控、单独写告警脚本,五个人根本不够分。
为什么不上容器和 K8s
这是被问得最多的一个决定。道理很简单:K8s 需要至少一个专职 SRE 心智,我们的服务只有三个,用 systemd 加 CVM 镜像挨个部署完全 hold 得住。等到服务超过十个、或者有了专门的运维同学,再迁容器不迟。CVM 的另一好处是计费直观,新购、升配、退款的账单一目了然,做成本治理时有据可查,这也是后来成本治理一篇能落地的前提。第一批三台机器在腾讯云 CVM 特惠期间购入,预算只占当月云支出的零头。
踩坑:版本选择别太追新
选型定下后的第一周就踩了版本坑。grpc-go 用了当时最新的 1.6x,结果 etcd 客户端的依赖有 conflict,编译过不去又回退了一个 minor 版本。此后我们定了一条铁律:核心依赖一律用上一个 minor 版本而非最新版,所有版本固定在 go.mod 里,升级必须有一个人专门 review。protobuf 工具链的版本也一并固定,否则 proto 生成代码格式天天变,diff 里全是噪音。
另一个坑是客户端兼容。移动端老版本用的是 JSON 接口,gRPC 上线时存量调用不可能一夜全切。我们的做法是网关侧同时提供 gRPC 与 HTTP 两种入口,新老流量按端版本灰度切换,老版本逐步淘汰。这要求网关能做协议转换,API 网关一节里展开了具体做法。
小结
选型的出发点不是够不够先进,而是你团队能 hold 住什么。我们的组合是 gRPC 加 protobuf 做服务间通信、gin 做对外 HTTP、CVM 做算力底座、RocketMQ 削峰、CLS 统一日志、云监控加 API 网关补齐治理能力。核心依赖不追新版本,固定且专人 review。下一章开始进入真正的上云实操:先在本地用 docker-compose 跑通最小集群,再一台台把服务搬上 CVM。
选型表不是一次定终身的合同。我们约定每半年 review 一次:哪一项变成了瓶颈、哪一项可以下掉。第二年的复盘里唯一调整的是把日志库从自封装换成了 CLS 官方采集器,其余全部沿用至今。一张选型表能撑两年,靠的不是眼光,是前面那三条朴素的原则。
延伸阅读
- 2.1 本地起一个最小集群:docker-compose 起步 —— 上云前先本地跑通
- 2.2 首次上云:CVM 实例选型清单 —— 底层算力怎么选
- 腾讯云 CVM 官方文档入口 —— 实例规格与选型参考
