One self-hosted console to run your entire business — commerce, ERP, HRM, CRM & manufacturing

扩展自托管电商平台:日订单从 100 到 100,000 的服务器路线图

分阶段扩展电商基础设施的实用指南:每个阶段该增加什么、哪些指标告诉你何时动手、什么最先出问题、零停机的蓝绿部署,以及真正能恢复的备份。

Author

Anichur Rahaman

2 个月前9 min read1 views
扩展自托管电商平台:日订单从 100 到 100,000 的服务器路线图

每个自托管电商平台的起点都一样:一台服务器、一个数据库,以及一个知道所有东西在哪里的人。这是正确的开始方式。它便宜、简单,对前一千位客户来说也足够快。

麻烦始于增长比架构变化来得更快的时候。一场限时抢购让某个下午的流量翻倍;一个快递接口每隔几秒就重试一次;一份财务报表在午间高峰扫描两年的订单。结账突然变慢,却没人说得清原因。

本文是我在规划电商与 ERP 系统基础设施时使用的扩展路线图。它分为四个阶段,从每天约 100 单到 100,000 单乃至更多。每个阶段都说明该增加什么、该测量什么,以及最重要的——什么最先出问题,让你在数字提示时调整架构,而不是等客户投诉时才动手。

服务器架构成长的四个阶段:单机部署、按角色拆分、横向扩展与服务器集群
成长的四个阶段。每一列列出了要增加的组件以及通常最先出问题的环节。

第一原则:先测量,再扩展

扩展成本高,而每个新组件都是又一个可能出故障的地方。在增加服务器之前,确保仪表盘上能看到以下五个数字:

  • p95 响应时间:首页、商品页、购物车和结账页。平均值会掩盖那些让你丢单的慢请求。
  • 数据库负载:活跃连接数、慢查询(超过 100 毫秒的都算)以及缓存命中率。
  • 队列深度与等待时长:有多少任务在排队,最早的一个已等了多久。
  • 每台主机的内存与交换分区,以及内核日志中的内存不足(OOM)终止记录。
  • 错误率:每分钟 5xx 响应数与每小时失败任务数。

如果看不到这些数字,第一个扩展项目就是可观测性。看不见的服务器,你一定会买多。

阶段 1 — 单机部署(每天约 1,000 单以内)

一台 4 核 vCPU、8 GB 内存、高速 SSD 的虚拟服务器,能支撑的业务量超出很多人的想象。用容器保持整洁:Web(nginx 后的 PHP-FPM)、PostgreSQL、Redis、一个队列工作进程和一个调度器。

这个阶段要做对的事

  • 开启 OPcache 并启用预加载。PHP 每个文件只编译一次并常驻内存。仅此一项通常就能把响应时间减半。
  • 服务提供者启动阶段不做任何工作。每个请求都会执行的逻辑(读取设置、构建菜单)必须缓存。每个请求多 10 毫秒,规模上来后就是一整颗 CPU 核心。
  • 慢任务放到后台。邮件、快递下单、图片转换和 PDF 发票都应进入队列,绝不放在结账请求里。
  • 异地备份,并经过验证。每晚把数据库导出到对象存储,每月做一次恢复演练。没验证过的备份只是希望,不是备份。

最先出问题的环节

内存。大型报表、数据导入或批量图片处理会和结账争抢内存。表现为页面随机变慢,最终内核杀掉某个进程。调度器常常是受害者:给它单独的内存上限(512 MB 是合理下限),并运行一个常驻的调度进程,而不是每分钟启动一个新进程。

阶段 2 — 按角色拆分(每天约 1,000 到 10,000 单)

下一步不是"同样的服务器买更大的",而是拆分角色,让它们不再互相争抢资源。

角色为什么拆出来典型配置
数据库主机独立的磁盘 I/O 和用于缓存的内存,没有"吵闹的邻居"。4–8 vCPU,16–32 GB 内存,NVMe
Redis 主机在高负载下,会话、缓存和队列依然快速。2 vCPU,4–8 GB 内存
Web 节点CPU 密集的 PHP 工作,可独立扩展。每台 2–4 vCPU
队列工作进程每个队列独立的进程池,邮件永远不会拖慢支付。每个池 2 vCPU

缓存访客看到的页面

商店的大部分流量是匿名访客在浏览商品和分类。这些页面可以在应用层和 CDN 上作为完整 HTML 缓存几分钟。两条规则可以避免棘手的问题:

  • 缓存键必须包含域名。如果商店同时使用两个域名,不含域名的缓存键会把一个域名的链接和脚本发给另一个域名的访客。
  • 绝不缓存任何个人化内容。购物车数量、登录客户的专属价格和账户页面,要在缓存的页面框架之后再渲染,或者完全不缓存。

最先出问题的环节

数据库连接与慢查询。每个 PHP 工作进程都会打开自己的连接。两个 Web 节点上的 40 个工作进程再加上队列进程,就可能超过 PostgreSQL 能舒适承受的连接数。同时,当表超过一百万行时,一个缺失的索引会让 5 毫秒的查询变成 900 毫秒。每周检查一次慢查询日志。

阶段 3 — 横向扩展(每天约 10,000 到 50,000 单)

此时在负载均衡器后运行多个相同的 Web 节点。系统必须做到Web 层无状态:会话放在 Redis,上传文件放在对象存储,任何 Web 节点的本地磁盘上都不存放重要数据。

请求路径:CDN、网关、带 PHP-FPM 的 Web 节点、Redis、PgBouncer 与 PostgreSQL;队列、调度器、SSR 与对象存储位于请求路径之外
请求路径。最下面一行的所有组件都必须在路径之外——顾客永远不应该等待队列任务。

这个阶段的关键组件

  • 连接池(PgBouncer)。数百个应用连接共享几十个真实的数据库连接。这往往是提升稳定性最大的一步。
  • 报表专用只读副本。仪表盘、导出和分析都从副本读取,大型报表不再拖慢结账。
  • 媒体与备份使用对象存储。S3 或兼容服务(如 Cloudflare R2),通过 CDN 分发。Web 节点完全不再负责提供图片。
  • 独立的 SSR 渲染服务。服务端渲染让页面更快、更易被搜索引擎收录,但它与 PHP 是不同的负载,需要单独扩展。
  • 队列监控。一个能显示每个队列吞吐量、失败数和等待时间并带告警的面板(例如 Laravel Horizon)。

最先出问题的环节

缓存击穿与热点行。当一个热门缓存过期时,数百个请求会同时尝试重建它。使用锁或"过期仍返回、后台刷新"(stale-while-revalidate),让一个请求重建,其余请求先返回旧值。另外,人人都要更新的那一行——抢购商品的库存计数器、某个序列号——会变成一排等待的事务。让这类更新尽量短小且原子化。

阶段 4 — 服务器集群(每天 50,000 单以上)

到了这个规模,技术模式已广为人知。真正变化的是围绕它们的工程纪律。

  • 队列分区,让支付、通知、搜索索引和 AI 任务各有专属容量。
  • 搜索与分析下沉到专门的引擎,由事件实时驱动,而不是靠每晚导出。
  • 历史数据归档存储。旧订单、日志和审计轨迹迁移到更便宜的存储,但仍可查询。
  • 多区域边缘节点,为静态资源和缓存页面就近服务客户。
  • 运维手册与值班制度。每个告警都有书面的首要处置步骤。我见过最糟糕的故障不是因为缺服务器,而是凌晨三点没人知道该做什么。

零停机部署:蓝绿发布

每次发版都要停机的商店,会让团队越来越少发版,而这又让每次发版风险更高。蓝绿部署可以打破这个循环。

蓝绿部署六步:只构建一次、启动绿色环境、仅做增量迁移、预热与检查、切换、保留蓝色环境以便回滚
新版本在线上版本旁启动、完成迁移并通过健康检查,之后流量才切换过去。
  1. 只构建一次。每次提交生成一个镜像,在 CI 中测试,从预发布环境原样推进到生产。
  2. 启动绿色环境,与正在服务的蓝色容器并行。
  3. 只做增量迁移。只新增列和表;同一版本中不重命名、不删除。旧代码必须能在新表结构上继续运行。
  4. 预热与检查。缓存配置与路由,访问健康检查接口,运行简短的冒烟测试。
  5. 切换网关上游时使用重载而非重启,确保不断开任何连接。
  6. 保留蓝色环境以便快速回滚。旧列在后续版本、确认无人读取后再删除。

用教训换来的经验:在准备新版本时清除线上版本的缓存或编译文件,每次部署都会让少量请求失败。请在独立目录中准备新版本,并在切换完成后立即清除一次应用缓存。

用大白话讲备份、RPO 与 RTO

两个数字决定了备份策略,应该由业务方而不是 IT 来选择:

  • RPO(恢复点目标):你能承受丢失多少数据。每晚备份意味着最多丢失 24 小时的订单。
  • RTO(恢复时间目标):恢复期间你能承受停机多久。
阶段合理的 RPO合理的 RTO做法
124 小时4 小时每晚导出数据库与文件到对象存储
21 小时1 小时每小时快照,脚本化恢复
3–4数分钟30 分钟以内持续 WAL 归档,热备副本

无论选择哪种方案,都要安排恢复演练。在 StoreConsole 中,备份模块会定时为数据库和文件创建快照、检查磁盘健康、执行保留策略,并支持一键恢复。下方的短视频展示了这一过程。

备份演示(0:46):定时快照、保留策略与一键恢复。

我反复看到的五个陷阱

  1. CDN 缓存了 404。如果页面先请求了一张图片、之后才上传,CDN 可能连续几小时返回"未找到"。先写入文件,再放链接。
  2. 在一种数据库上通过、在另一种上失败的测试。测试用 SQLite、生产用 PostgreSQL,二者在大小写敏感搜索、类型比较和枚举变更上表现不同。至少让一个 CI 任务跑在生产同款数据库上。
  3. 在生产主机上执行大型构建。同时运行两个前端构建可能耗尽内存导致商店宕机。在 CI 中构建,发布镜像。
  4. 用普通 shell "&" 启动的后台进程。会话结束它们就跟着退出。请使用进程管理器或容器运行时。
  5. 生产环境遗留调试工具。查询监听器和性能分析器会给每个请求增加开销,被遗忘的监控进程可能悄悄吃掉一颗 CPU 长达数周。

今天就能用的容量检查清单

  • 最繁忙时段的 p95 结账时间低于 800 毫秒。
  • 高峰期数据库 CPU 低于 60%,结账路径上没有超过 100 毫秒的查询。
  • 支付与通知队列中最早的任务等待少于 60 秒。
  • 高峰期每台主机至少保留 30% 空闲内存,过去一周零次 OOM 终止。
  • 最近一次恢复演练在 30 天以内。
  • 每次发布都能零停机部署并可回滚。

如果你正在为 StoreConsole 规划硬件,系统要求页面列出了各阶段的推荐配置,文档涵盖 Docker、队列与调度器。

要点回顾

  • 当指标提示时再扩展:p95 延迟、数据库负载、队列等待时长、内存、错误率。
  • 阶段 1 是一台调优良好的服务器;阶段 2 按角色拆分;阶段 3 借助连接池、只读副本和对象存储横向扩展;阶段 4 关乎工程纪律。
  • 让慢任务远离请求路径,顾客永远不应等待队列任务。
  • 采用仅增量迁移的蓝绿部署,并保留旧版本随时回滚。
  • 由业务方选择 RPO 与 RTO,然后按计划演练恢复。

Anichur Rahaman 是一名软件架构师,也是 StoreConsole 的创建者。他为成长型企业设计电商与 ERP 系统,专注于事件驱动架构、数据完整性和自托管运维。

About the Author

Anichur Rahaman