安全与合规高并发系统的安全与发布:加固的边缘层与零停机部署
从 CDN、WAF 到私有网络的安全分层,以及由滚动发布、blue/green 和 expand and contract 迁移组成的交付流水线,最后附上流量尖峰当天的上线清单。
预定的流量尖峰在几秒内到顶,而新服务器要几分钟才能就绪。本文讲清突发流量下什么能扩、为什么预扩容胜过响应式规则、如何配置 SSR 和 PHP-FPM 层,以及怎样做压测。
Author
Anichur Rahaman

每秒 20 个请求,平平稳稳。限时抢购开始前的晚上 11:59,一家网店的流量只有这么多,平台负责人正盯着监控面板。自动扩缩容(autoscaling)规则已经就位:CPU 连续五分钟超过 70%,就加一台服务器。(这是一个示意性的场景,并非真实店铺。)
午夜,抢购开始,大约一千名买家在同一分钟里同时涌入。负载一下跳到每秒 440 个请求。12:01,监控面板还是绿的,因为五分钟的平均值几乎没动。12:03,结账开始超时。新服务器在 12:06 才加入,那时买家早已去了竞争对手那里。
自动扩缩容是在负载出现之后才做出反应,而预定的尖峰恰恰赶在这个反应之前到来。本文讲的是:突发流量下什么真正能扩,什么不该指望它去扩,以及怎样在活动之前而不是活动当中把这件事弄清楚。
下面的数字来自我自己在同一套 Laravel + Next.js 环境里的测试。它们演示的是方法,不是通用基准,请在你自己的系统上重新测一遍。
本文是五篇系列“高并发系统工程”的第 1 篇,讲从边缘到应用的请求链路。队列、数据层、可观测性和安全发布,会在第 2 至第 5 篇展开。
两种流量形态,需要两种不同的应对。缓慢上升给了任何控制回路发现并响应的时间;阶跃式跳升则不给。如果负载在一分钟内从每秒 20 个请求跳到 440 个,一条盯着五分钟平均 CPU 的规则,这时还什么都没看到。
好消息是,预定的尖峰是可以预测的。你知道开始时间,大致知道会来多少人,往往还能把上一次活动的请求组合重放一遍。这种提前量是你最大的工具,本文大部分内容就是讲怎么用好它。
决定扩什么之前,先把一个请求走过的路径画出来。在我运行的环境里,它是这样的:最前面是 CDN 和 WAF,接着是托管的负载均衡器,两个后端 Web 节点,一个或多个服务端渲染(SSR)前端节点,一个处理后台任务的 worker 节点,最后面是数据层。

每个方框都有自己的故障模式和扩展手段。把它们当成一台“服务器”,结果往往是给从来不是瓶颈的那一层加内存。
先在最前面放一个 CDN。静态文件、图片,以及所有访客看到都一样的页面,尖峰期间根本不该到达你的服务器。同一层的 WAF 和机器人规则,还能挡住爬虫,免得它们吃掉你留给买家的容量。
CDN 后面用带健康检查和连接排空(connection draining)的托管负载均衡器。健康检查会自动摘掉有问题的节点;连接排空让节点在离开前先处理完手头的请求,发布和缩容因此对用户无感。
有两个细节值得核对。第一是调度算法。不少云负载均衡器默认用轮询(round robin),它假定每个请求的开销一样。结账和搜索显然不是。“最少未完成请求”或“最少连接”模式,会把下一个请求交给手上活最少的节点。以 AWS 为例,Application Load Balancer 默认是轮询,最少未完成请求是目标组上的一项设置。第二,负载均衡器本身也是需要扩容的服务。AWS 文档说明,Application Load Balancer 大约能在五分钟内把容量翻倍,并提供预留容量,用于五分钟内流量增长超过一倍的活动(见容量预留指南)。其他云厂商也有类似的限制,建议问清楚你用的那家。
在我的压测里,负载均衡器从未成为瓶颈:最高请求速率下 CPU 始终不超过 8%,零错误。这很典型,先去链路更深处找。
只有任何一个节点都能处理任何请求,才能把两个 Web 节点放到负载均衡器后面。这个特性叫无状态(stateless)。一开始做对很便宜,事后补救却很痛苦。加第二个节点之前,先对照这份清单。
像 StoreConsole 这样的自托管平台,正是出于这个原因把会话和缓存放在 Redis 里,让节点可以互相替换。
这是最让我意外的地方。Next.js 服务器在 Node.js 进程里渲染页面,而 Node 用单线程执行 JavaScript。机器再大,一个进程在渲染上也只能用到大约一个核。
我用 k6 重放了上一次高峰的真实请求组合,只打一个前端进程。它在每秒约 220 到 250 个请求时饱和。之后 p95 延迟从约 260 毫秒跳到约 3 秒,p99 达到 6.4 秒,而这一路宿主机上还有两个以上的空闲核。真实活动的高峰分钟需要每秒约 440 个请求,也就是说,一个进程会在最关键的那一刻失守。
解决办法很朴素:用同一个镜像跑多个一模一样的前端容器(我的例子是三个),前面用 nginx 的 least_conn,把每个请求交给活跃连接最少的服务器,然后按目标速率重新压测。Next.js 还有一点要注意:默认每个实例都有自己的本地缓存,所以多实例时,应按框架文档的做法改用共享缓存存储。
这里的容量规划就是简单的乘法:用实测的单进程上限乘以进程数,再和预期的高峰对比,并留出余量。
| 项目 | 数值(一套环境) | 说明 |
|---|---|---|
| 高峰分钟的需求 | ~440 req/s | 来自重放上一次真实活动 |
| 单个 SSR 进程,实测 | 220-250 req/s | 超过后 p95 从 ~260 ms 升到 ~3 s |
| 三个 SSR 进程 | ~660-750 req/s | 约为高峰的 1.5 倍,作为余量 |
| 负载均衡器 CPU | 8% 或更低 | 不是瓶颈 |
后端 Web 层的问题正好相反。PHP-FPM 运行一个 worker 进程池,每个 worker 一次只处理一个请求。池太小,请求就排队;池太大,节点内存耗尽,开始交换或杀进程。
一条好用的经验公式:需要的忙碌 worker 数 ≈ 每秒请求数 × 平均单次请求耗时。举个示意性的例子:每秒 200 个请求、每个 150 毫秒,大约需要 30 个忙碌的 worker,所以设 60 的池子能给慢请求留出空间。然后核对内存:如果单个 worker 占约 100 MB,60 个就要约 6 GB,节点内存必须比这更大。
我在一套环境里用的参数是 pm.max_children=60、start_servers=30、min_spare_servers=20、max_spare_servers=30、max_requests=1000,并在 nginx 与 FPM 之间启用长连接(keepalive 16 和 fastcgi_keep_conn on)。起步 30 个很重要:浪涌到来时池子已经热好了,不用在压力下临时 fork。
还有两个习惯值得养成。生产环境开启 OPcache 并设 validate_timestamps=0,发布时重启 worker。另外可以考虑 fastcgi_next_upstream error timeout http_500 http_503 配合 fastcgi_next_upstream_tries 2,它把 FPM 偶发的小故障变成了静默重试。注意这只对幂等请求安全。重试一个支付 POST 不是修复,而是 bug。
现在说核心观点。响应式扩容要先盯指标,等阈值被突破,再启动机器,再等它开机、加入负载均衡器、预热缓存。实际上这最快也要一到三分钟。默认配置还可能更慢:比如 AWS EC2 Auto Scaling 的默认冷却时间是 300 秒,基础监控每五分钟才发布一次实例指标,除非你付费开启一分钟粒度的详细监控。
预定的尖峰在几秒内就到顶了。新机器赶到时,人已经走了,更糟的是,他们已经看到了报错。虚拟机不重启也没法加内存,所以“原地加大”同样行不通。

对预定的活动,在开始前把节点数下限调高,结束后再调回去。这比听上去便宜:多开几个小时的一个节点,成本远低于一场失败的促销。它也比任何规则更可靠,因为它不依赖某个指标恰好及时越线。
响应式规则留作应对意外的安全网,不要当成主方案。还要扩那些扩得快的东西。容器内的进程几秒钟就能启动,机器则要几分钟,这也是我按进程而不是按机器来扩队列 worker 的原因(见本系列第 2 篇)。
| 方式 | 响应时间 | 最适合 |
|---|---|---|
| 预扩容(调高下限) | 活动前已就绪 | 预定的尖峰 |
| 响应式虚拟机扩容 | 1-3 分钟或更久 | 缓慢增长、计划外流量 |
| 进程级扩容 | 几秒 | 容器内的队列 worker |

上面没有一个数字是猜出来的,都来自贴近真实活动的测试。只猛压首页,几乎证明不了什么。按这个顺序来。
在测试证明上限在哪里之前,不要升级硬件。我这次机器本身没问题,上限是单线程进程,修复只花了配置的功夫。
把开头的场景再演一遍,这次准备到位。晚上 11 点,Web 节点的下限从两个调到三个,SSR 层在 least_conn 后面跑三个进程。缓存已经预热,FPM 进程池一开始就有 30 个 worker。
午夜时分,每秒 440 个请求涌来。实测上限约 660,所以 p95 基本维持在平时的水平,而自动扩缩容规则一次也没触发,因为根本用不上它。12:30,下限调回原值。整场活动的成本,只是多开了几个小时的一个节点。
这条链路后面的几层,出问题的方式不一样。突发流量下,后台任务通常最先崩,第 2 篇讲大规模队列与 worker。第 3 篇转向高负载下的数据层,第 4 篇是可观测性,第 5 篇是安全与零停机发布。想判断业务增长时需要多大的服务器,可以看我之前那篇服务器扩容路线图。
Anichur Rahaman 是一名软件架构师,也是 StoreConsole 的创建者。他为成长型企业设计电商与 ERP 系统,专注于事件驱动架构、数据完整性和自托管部署。
About the Author
Anichur Rahaman
Continue Reading