换服务器前先算三个数:峰值 QPS、并发与内存的实测换算

一、先把「选服务器」拆成两个问题

个人站长换服务器,问得最多的是「阿里云还是腾讯云」「香港的还是日本的」「要不要上独服」。这些问题其实都跳过了第一步。真正决定你买什么的,不是厂商和地域,而是两个具体数字:你的站峰值能扛多少并发请求,以及这些请求里有多少是动态的。

先说为什么是这两个。一个纯静态的站,同样的机器能扛住十倍于动态站的并发,因为前者只是把文件从 page cache 里读出来写进 socket,后者每一个请求都要走 PHP-FPM、连 MySQL、拼模板。很多人买服务器时按「内存越大越好」去挑,结果升级到 8G 之后页面依然卡——因为瓶颈在 PHP-FPM 的进程数,不在内存总量;也有人买了高主频低核数的机器,跑动态站反而不如核数多一点的。

我自己的判断顺序是:先测出现有站的峰值 QPS 和动态请求占比,再按「动态请求 = 并发上限的决定因素」倒推 CPU 核数与 PHP-FPM 进程数,最后才是内存和带宽。这篇文章按这个顺序走一遍,每一步给出具体命令和判据。

需要先说清楚的是,这里讨论的是「已经有一个站,要决定买什么机器」的场景,属于选型的前置计算。如果你手上还没有站点数据,可以先按经验给一个粗估,上线一个月后再回到这里重新算一遍——第一次算出来的结果几乎总是偏大,因为人对自己站的流量预期普遍偏乐观。

二、测峰值:不要用「日均 PV」做决定

服务器的配置是按峰值买的,但大部分人对自己的峰值一无所知。日均 3000 PV 的站,如果 70% 的访问集中在晚上八点到十点,那两小时的瞬时 QPS 可能是日均值的五到十倍。

最准的数据来源是 Nginx 日志。按分钟聚合请求数,找出最高的一分钟:

awk '{print substr($4, 2, 17)}' /var/log/nginx/access.log \
  | sort | uniq -c | sort -rn | head -10

输出会是这样:某一分钟 412 个请求,即 6.9 QPS;第二高 380。这就是你的真实峰值基线。注意这是「日志里最忙的一分钟」,如果那天有活动或转载带来的突发,这个数会更真实。

但日志只记录了到达服务器的请求。还有一种峰值日志看不见:搜索引擎集中抓取。如果某天 sitemap 更新后爬虫蜂拥而至,日志会显示出来,但那已经是被打过一次的峰值。所以做规划时,通常在这个峰值上乘以 2 到 3 作为安全系数——不是浪费,而是给爬虫突发、缓存失效后的回源洪峰留出余量。

还要区分「请求」和「有效请求」。日志里通常有 20%~40% 是静态资源(css/js/图片/favicon),这些请求的代价远低于动态请求。按扩展名分一下:

awk '{print $7}' /var/log/nginx/access.log \
  | grep -oE '\.[a-z0-9]{2,5}$' | sort | uniq -c | sort -rn | head -12

如果 .html 或 .php 占不到一半,说明静态占比高,机器可以买弱一点;反之则要把钱花在 CPU 和 PHP-FPM 上。

三、并发换算:利特尔法则的一个简化用法

QPS 和并发数不是同一个东西。QPS 是「每秒完成多少个请求」,并发是「同时有多少个请求在处理中」。两者的关系是利特尔法则:并发 = QPS × 平均响应时间。

举个实际例子。你的站峰值 20 QPS,页面平均响应时间 200ms(0.2 秒),那么平均并发 = 20 × 0.2 = 4。也就是同一瞬间只有 4 个请求在处理,其余都在等。这意味着 PHP-FPM 只要有 8~10 个进程就足够应付平均情况——但因为流量有波动,实际需要的进程数通常是这个值的 3 到 5 倍,取 30 个左右。

这个算法被很多人忽略,结果买了一台 16 核的机器,配了 50 个 FPM 进程,然后发现 MySQL 先撑不住。因为真正限制你的往往不是并发数本身,而是并发带来的后端压力。

什么时候这个简化算法会失效?当平均响应时间不稳定时。如果 95% 的请求是 50ms,5% 是 3 秒(某个慢查询或外部 API 超时),平均响应时间会被拉高到 200ms 以上,而实际的进程占用是被那 5% 的慢请求长期霸占的。这种情况下并发数会远高于利特尔法则算出来的值,进程池会被慢请求吃光。所以算之前,先看响应时间的分布而不是平均值:

awk '$9==200 {print $NF}' /var/log/nginx/access.log \
  | sort -n | awk '{a[NR]=$1} END {print "p50",a[int(NR*0.5)],"p95",a[int(NR*0.95)],"p99",a[int(NR*0.99)]}'

如果 p99 是 p50 的二十倍以上,先去治慢请求(加索引、加缓存),再谈买机器。买机器掩盖不了慢查询,只会让账单变长。

四、内存:按进程数倒推,而不是按「越大越好」

PHP-FPM 的内存占用是可测的。用这条命令看每个 worker 的实际 RSS:

ps -o rss= -C php-fpm | awk '{s+=$1; n++} END {print "进程数",n,"平均",s/n/1024"MB","合计",s/1024"MB"}'

个人站通常每个 worker 占 25~60MB,取决于加载了多少扩展和框架。假设实测 40MB,你计划配 30 个进程,那么 FPM 峰值内存 = 30 × 40 = 1200MB。再加上 MySQL(保守 512MB)、系统与 Nginx(300MB),总计约 2GB。买 4G 的机器就有近一倍的余量,够应付突增和系统缓存。

这里有一个常见误区:把「内存」当成缓存来用。Linux 会用空闲内存做 page cache,看起来「内存总是满的」是正常现象,不是内存不足。判断内存是否真的紧张,看的是 available 而不是 free:

free -m
grep -E 'MemAvailable|SwapFree' /proc/meminfo

如果 MemAvailable 长期低于总量的 15%,并且 swap 有持续读写(vmstat 1 的 si/so 两列非零),那才是真的不够。这时候买更大的机器是对的;如果 available 还有一半,买内存纯属浪费。

另一个细节:MySQL 的 innodb_buffer_pool_size 是「买内存」的最正当理由。如果你的数据量在 500MB 以内,buffer pool 能全装下,查询几乎不落盘,这时候加内存的收益是最明显的。数据量 2G 以上,buffer pool 装不全,加内存只能提高命中率,边际收益递减,不如先优化查询。

五、CPU:核数、主频与 PHP 的关系

PHP 是单线程执行请求的,一个请求占一个核(严格说是占一个 CPU 时间片)。所以 PHP 站的 CPU 需求基本等于「并发处理中的动态请求数」,而不是核数越多越好。6 核跑 30 个 FPM 进程,同时最多有 6 个请求在真正跑,其余 24 个在排队——这个比例是健康的,因为排队时间短。

什么时候核数不够?当 top 的 load average 持续高于核数,且 %wa(IO wait)不高时。如果 load 高但 wa 也高,说明在等磁盘 IO,加核没用,要换 SSD 或加内存减少磁盘读。

主频对 PHP 的影响比核数更直接。同样的代码,3.5GHz 的单核比 2.2GHz 的快 40% 以上。个人站并发不高(利特尔法则算出来个位数),买高主频的 2 核机器,往往比低主频的 8 核机器跑得更快。云厂商的「共享型」实例主频经常只有 2.0~2.2GHz,而且有 CPU 积分限制,跑满会限速——这就是为什么同样标称 2 核,共享型和计算型体感差很多。

选型的实用建议:动态为主的站,优先选通用型或计算型(独享 vCPU),核数按「峰值并发 × 2」估;静态为主的站,选共享型就够,钱花在带宽和 SSD 上更值。

六、带宽:算清楚一个月跑多少 GB

带宽的坑在于单位混乱。云厂商说的「5M 带宽」是 5Mbps(兆比特每秒),换算成下载速度大约 640KB/s。一个页面 200KB,理论上 3 个用户同时打开就打满了。但实际情况是页面资源分散在多个请求里,且浏览器并发连接,所以 5M 带宽大约能支撑 10~15 QPS 的静态资源请求。

月流量的算法:页面平均大小 × 月 PV × 1.5(缓存失效和爬虫的重复请求)。如果平均页面 300KB,月 PV 10 万,月流量约 45GB。很多云厂商的按流量计费是 0.5~0.8 元/GB,45GB 也就二三十块;但如果你的站有视频或大图,这个数字会轻松翻十倍,此时必须上 CDN 或对象存储。

判断要不要 CDN 的标准很简单:看带宽账单和回源比例。如果带宽费用超过机器费用的 30%,或者单月流量超过 500GB,CDN 就是划算的。但要注意,CDN 对 HTML 的加速效果有限(缓存时间短,TTFB 改善不明显),收益主要来自静态资源。所以「上 CDN 让动态页变快」这个预期是不成立的,动态页的加速要靠缓存和数据库优化。

地域选择上,国内站必须备案,这个没有折扣;面向海外的站,香港节点的延迟对大陆用户友好但带宽贵,日本节点性价比高,美国节点最便宜但国内访问延迟 150ms 以上。个人站的经验是:受众在哪里就放哪里,不要为了「便宜」把站放到目标用户的对侧——延迟带来的跳出率损失远大于省下的几十块钱。

七、磁盘与 IOPS:最容易被忽略的一项

买机器时大家盯 CPU 和内存,很少看磁盘类型。但个人站最常出现的「玄学卡顿」,有一半来自磁盘 IO 性能不足。云盘的 IOPS 通常按容量线性给(比如每 GB 给 30 IOPS),一块 40G 的系统盘可能只有 1200 IOPS,跑 MySQL 高峰时随便就撞顶。

判断当前是否被磁盘限制:

iostat -x 1 5
# 关注 %util 接近 100 且 await(平均等待毫秒)持续大于 20 的情况

如果 %util 长期在 80% 以上,先看是不是日志写太猛(Nginx access log、MySQL binlog、慢日志),再考虑升盘。SSD 云盘相比普通云盘的 IOPS 高一到两个数量级,对 MySQL 和小文件读写的改善非常直接,通常是升级性价比最高的一项——比加内存便宜,比换 CPU 有效。

另外要注意容量的余量。磁盘用到 90% 以上时,文件系统碎片化加剧,写入性能下降明显,MySQL 也可能因为临时表空间不足报错。规划时按「当前用量 × 2」买盘,比按「够用就行」省的麻烦多得多。

八、一张按瓶颈类型选型的对照表

把上面的判断收成一张表,选型时直接对着看:

瓶颈在 CPU(load 高、wa 低、FPM 队列长):升主频或加核,优先独享型实例;同时检查是不是有死循环或未缓存的模板编译。

瓶颈在内存(available 低、swap 有读写、MySQL 命中率低):加内存,并把 innodb_buffer_pool_size 提到物理内存的 50%~60%。

瓶颈在磁盘(%util 高、await 高、慢查询里大量 filesort/temporary):换 SSD 云盘,加大容量;同时优化查询。

瓶颈在带宽(响应慢但 CPU 内存都闲、静态资源加载慢):上 CDN 承载静态资源,或升带宽。

瓶颈在连接数(FPM 报 max children reached、Nginx 报 worker_connections exceeded):先调进程池与 worker_connections,再看 max_connections,不要直接换机器。

最后一句实话:个人站的流量曲线通常是「长期平缓、偶尔尖峰」,为尖峰买大机器不划算。更合理的策略是买一台「刚好够日常、尖峰靠缓存和 CDN 顶」的机器,把省下来的钱花在备份和监控上——这两样东西平时看不出价值,出事的时候是唯一能救你的。

Last modification:November 12th, 2026 at 09:24 pm

Leave a Comment