1.2 选型对比:云开发与自建后端

场景

朋友的第一版小程序是两年前找人外包做的,传统套路:一台云服务器跑 PHP,MySQL 存数据,图片丢在同一台机器上。凑合着卖了一阵货,问题慢慢全冒出来——大促那天并发一上来,图片把带宽占满,商品列表要七八秒才刷出来;下单接口没做原子扣减,超卖了一百多单,一一打电话道歉退钱;最狠的一次是支付回调因为服务器负载太高没及时处理,有六十几笔付了钱但订单没翻转,客服电话接到手软。

我帮她复盘过那次大促的时间线:上午十点流量进来,十点零五分图片带宽跑满;十点二十分下单接口开始报 502,库存表被并发更新撞飞;十一点回调积压,支付成功的订单状态卡在待付款。每一步都不是玄学,全是可以预料的基础设施瓶颈。

更麻烦的是这套旧系统已经没人能完整说清楚:接口文档过期三年,部署脚本是外包离职前留下的,服务器上还同时跑着一个过滤订单的定时任务,谁也不敢动。每次想修一个问题,都要先花半天考古。朋友的原话是:能不能不重买服务器、也不再雇运维,把这堆烂事一次性解决了。我盘了一下她的团队:三个店员、一个兼职设计、我一个兼职开发,没人会运维,没有监控值班,预算一年不超过两万。

这个条件基本排除了自建后端的正经做法——自建不是写不出来,是养不起。于是我给了她一个判断:不是云开发在所有场景都更好,而是在“没人、没钱、没运维”这个场景里,它是唯一能把事办成的方案。但这话不能只凭感觉,我把账一笔笔算给她听。

方案

我把选型拆成五个维度打分:开发速度、运维负担、伸缩能力、月度成本、数据迁出。每个维度按她们的实际条件给权重,而不是按行业惯例。

维度 自建后端 云开发 CloudBase 她的条件偏向
开发速度 两周起(接口、鉴权、部署) 三天出第一版 云开发
运维负担 要盯服务器、升级、备份 免运维,控制台看日志 云开发
伸缩能力 大促前手动扩容 云函数自动扩缩 云开发
月度成本 服务器加带宽固定开销 按量付费,闲置近乎零 看阶段
数据迁出 数据库在手里 可导出,但接口要改 自建

自建唯一的优势是“数据在自己手里”和长期摊薄成本,可这两点对她都不成立:两年外包留下的代码已经是屎山,没人维护;固定开销在淡季纯属浪费。她真正的问题是“怎样在下个大促前不超卖、不丢单、图能秒开”,这是一个交付速度和稳定性的问题,不是所有权问题。

我也给出如果条件不同的反向结论:如果团队里有专职运维、日均订单上万、有一堆定时任务和消息队列要跑,那自建或云服务器方案更合适,控制力和成本都更优。选型没有标准答案,只有匹配度。我给朋友总结了三个自问,后来遇到新项目我都先过一遍:

一问团队:有没有能持续投入的运维人力?没有就优先托管。 二问阶段:业务是稳定可预测,还是大促波动剧烈?波动大就优先弹性伸缩。 三问问题:当前最痛的是什么?是交付速度、稳定性还是成本?选型要冲着最痛的那一刀去。

她的回答分别是“没有运维、大促波动剧烈、最痛丢单和超卖”,三条全指向云开发,讨论五分钟就定了。

配置/代码

光讲道理没用,我把钱也算明白了。以她每月十二万流水、大促日两千单的规模,两种方案一年的账是这样的(云开发按云函数调用次数、云数据库容量和 CDN 流量估算):

项目 自建后端 云开发
计算资源 服务器 2 核 4G 约 90 元/月 云函数约 120 万次/月,约 40 元
数据库 自带 MySQL,含服务器内 云数据库 5G 内免费档
图片存储 同服务器,带宽另算 云存储加 CDN,约 60 元/月
大促扩容 临时升配约 300 元/次 自动扩缩,不额外掏钱
人力运维 隐形,死一次赔一天销售额 接近零

她看完这张表就不再纠结了:自建便宜的那点钱,不够一次超卖事故的赔偿。确定方案后,我在小程序端初始化云开发环境,三行代码就连上后端:

// app.js
wx.cloud.init({
  env: "mini-shop-prod",   // 云开发环境 ID
  traceUser: true
});

初始化之后,前端就能直接读写云数据库、上传云存储、调用云函数,不用配业务域名、不用给接口备案、不用管 HTTPS 证书。对比之前外包那套改一次接口要登服务器的流程,效率差了一个数量级。后端第一个跑通的接口是商品列表,一个云函数就完事:

// 云函数 getGoods/index.js
const cloud = require("wx-server-sdk");
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });

exports.main = async (event) => {
  const { page = 1, size = 20 } = event;
  const db = cloud.database();
  const res = await db.collection("goods")
    .field({ title: true, cover: true, price: true })
    .skip((page - 1) * size)
    .limit(size)
    .get();
  return { list: res.data, page };
};

这一段代码把之前外包那套 PHP 加路由加鉴权加部署的流程压缩成一次部署,朋友在旁边看着从零跑通接口,当场拍板按这个方案重写。环境上我们还做了一点规划:开两个环境,mini-shop-prod 给正式用户,mini-shop-dev 给开发调试,两个环境的数据和云函数互相隔离,测试环境随便造数据都不会污染线上订单。

环境 用途 注意事项
mini-shop-dev 日常开发联调 可随便造数据
mini-shop-prod 线上正式环境 严禁手动改数据
体验版 内测给店员试用 走开发环境即可

小程序端通过 wx.cloud.init 里的 env 字段切换环境,发布正式版前检查一遍 env 指向,这个动作后来变成我们的发版清单第一条,因为某次把 dev 环境发到了门店,顾客下单落进了测试库,排查了一下午。

踩坑

第一个坑是低估了旧系统迁移的脏。旧 MySQL 里的商品分类字段既有中文名又有编码,库存数据散在两个表里对不上,同一款杯子在两个表里库存差了十几件。我写脚本迁到云数据库时图快没做清洗,第一天测试就出现库存负数,废了半天手动修数据。结论:迁数据前先做一次离线对账,把脏数据挡在门外,别指望新系统自带容错。

第二个坑是云函数冷启动。大促不是整点均匀来流量,经常是某个整点突然一波,冷实例没预热,第一批请求慢了将近两秒,正好赶上用户最没耐心的时候,跳出率明显偏高。后来做了两件事:给下单云函数保留最小实例数,并在活动开始前用定时器打一波预热请求。这个细节在监控告警那节会展开,配置一次之后大促再没出现首波卡顿。

第三个坑是工具链锁定的心理负担。朋友听说无服务器架构,担心被平台绑死,要求预留迁出方案,甚至问能不能每周导一次全量数据到自己电脑。我的做法是:业务代码只写纯函数逻辑,云开发 SDK 的调用集中在入口层,真要迁的时候换入口即可;另外云数据库本身支持导出 JSON 快照,她的安全感需求顺手满足。实际证明这个约束不难遵守,也没有增加开发量。

第四个坑是云函数超时配置。默认 3 秒,下单链路里要查库存、扣库存、调微信支付统一下单接口,大促时偶尔排队超过 3 秒就被掐断,顾客看到“系统繁忙”直接流失,那天大概损失了二三十单。把超时调到 10 秒、同时砍掉链路里一次多余的数据库查询后才解决。

第五个坑是带宽焦虑。她被旧系统图片拖垮过,总觉得图片会再次拖垮新系统。其实云存储走的是对象存储加 CDN 的链路,和小程序接口完全分离,图片再多也不会挤占下单接口的带宽。搞明白这一点之后,她在商品详情上的构图大胆多了,详情图从每款五张加到八张,首屏反而更快了。

小结

选型这件事,脱离团队条件谈技术优劣是耍流氓。小团队、兼职开发、预算有限、大促两小时峰值——云开发在这种场景下的优势不是“更先进”,而是把运维、扩容、证书、备份这些活按量计费地包出去了,让唯一一个开发能把时间花在交易链路的正确性上。重中之重是先回答“团队、阶段、痛点”三问,再谈技术栈;账算到月、责任落到人,老板才敢拍板。后来每次有同行问我该选什么,我都先把这三问抛回去。要论对高并发系统更全面的权衡,可以参考云服务器上的实践合集里的对比框架;如果你团队里反而有运维人力,轻量云服务器建站那套思路更对味。下一节进入实操:开通云开发环境和小程序账号的具体步骤。

延伸阅读