接手这个需求时,第一反应是:用现成方案不是更方便吗?但仔细分析业务场景后,发现有几个特殊约束确实绕不开,这才促成了这套自研框架的诞生。

需求分析
自研框架在设计上借鉴了 Laravel 的核心思想(服务容器、中间件管道、门面模式),但去掉了反射机制和大量 Composer 依赖。最终核心代码只有约 200KB,在低配服务器上的性能比 Laravel 高出 30%-40%。从实际效果看,这个取舍带来的收益相当可观。
方案对比
先梳理一下市场上的主流选择。大致有三条路:完全自研、基于开源系统二次开发、或者直接使用成熟的 SaaS 系统。每种方案的适用场景和隐性成本差异很大,需要结合自身情况仔细权衡。
完全自研的优势在于可控性强,但前期框架搭建和后期维护成本都很高。开源系统虽然省去了基础代码,但遇到特殊的业务逻辑,改起来可能比从零开始更费劲。至于 SaaS 系统,开箱即用是最大优点,但长期看,数据安全、定制化灵活性以及定价模式都需要仔细评估。
选型理由
最终选型主要卡在三个硬性约束上:服务器预算有限,只能上 2C4G 的轻量云服务器;整个后端开发由我一人承担;客户要求两周内上线。在这样苛刻的条件下,开箱即用的方案成为最务实的选择。
实际开发中遇到的一个典型难题是 1688 API 的限流处理——每个 AppKey 每秒只能调用 20 次。最终我们引入消息队列(RabbitMQ),配合令牌桶算法来控制消费速率。印象最深的一个坑:1688 临时维护了 2 小时,导致所有请求失败后不断重试,消息积压了 3000 多条,直接造成 RabbitMQ 内存溢出。后来通过设置消息 TTL(5 分钟)、死信队列和最大重试 3 次的机制,才算彻底解决这类问题。
代码实现
下面这段状态机代码,是项目从初期到后期演进的缩影。最开始只定义了 5 个状态,跑着跑着发现“待采购”和“已采购”之间少了一个“采购中”的中间态——因为 1688 下单可能需要 3-5 秒,这期间如果用户手快重复点击,就会触发重复采购。加上这个中间态,问题迎刃而解。
// 订单状态机演进:从 5 个状态扩展到 8 个
// 早期只定义了 5 个状态,后来发现 '待采购' 和 '已采购' 之间
// 少了一个 '采购中' 中间态——1688 下单可能耗时 3-5 秒,这期间
// 如果用户重复点击,会触发重复采购。加了这个中间态后问题彻底解决
const ORDER_STATES = {
PENDING: 'pending', // 待支付
PAID: 'paid', // 已支付
PURCHASING: 'purchasing', // 采购中(防重)
PURCHASED: 'purchased', // 已采购
ARRIVED: 'arrived', // 已入库
PACKED: 'packed', // 已打包
SHIPPED: 'shipped', // 已发货
COMPLETED: 'completed', // 已完成
};
方案局限
除了写代码和做运维,售后技术支持也一并负责了。客户反馈的 bug、数据库异常、接口故障,都要直接上手排查。一线经验让我写代码时更注重可维护性和可观测性——毕竟自己挖的坑早晚要自己填。
当然,这个方案也有明显的局限。单机部署决定了扩展性有限,如果未来租户数翻倍,服务拆分是迟早的事。另外,文件缓存在高并发场景下不如 Redis 稳定,这也是后续需要重点改进的方向。
这套架构跑了一年多,最大的感悟是:好的架构不是设计出来的,而是演进出来的。保持简单,等真正需要的时候再重构。这一点,比任何技术选型都重要。
