香港服务器 CPU 选型:频率优先还是核数优先?电商 p99、数据库 OLTP、离线转码三大场景 CentOS 7 实测对比

双 11 前,我们的香港节点要扩两柜。业务方给了三个诉求:
- 电商前端高并发抢购接口的 p99 延迟必须守住;
- 核心 MySQL 集群既要 稳 又要 能扛写;
- 一组 H.264/H.265 离线转码要在成本内尽可能吞吐。
销售同学问得很直接:“要不要上 64 核的大饼?还是高频 8 核更稳?”我没直接回答。经验告诉我,不同工作负载的瓶颈完全不一样,必须把 频率优先 与 核数优先 两种路线,在同一环境下 可复现地跑一遍,把数给业务看。
测试与部署基线(可复现)
机房与网络
- 机房:香港将军澳,双电双路,A+B 供电
- 上联:两条 10 GbE,LACP,Bare metal 直挂
- 实测延迟(ICMP):广州 14–18 ms,上海 22–28 ms,北京 34–40 ms
- 同一 VLAN 内部压测,避免外网波动
操作系统与内核
统一使用 CentOS 7.9(用户侧要求),内核 3.10.0-1160(保持与线上一致)
关键基线调优(三台一致):
# CPU 性能模式
yum install -y tuned && tuned-adm profile latency-performance
yum install -y kernel-tools && cpupower frequency-set -g performance
# 关透明大页,降 swappiness
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo "vm.swappiness=1" >> /etc/sysctl.conf
# NVMe 使用 none 调度器
for d in /sys/block/nvme*/queue/scheduler; do echo none > $d; done
# 网参(保守值,避免过度激进)
cat >> /etc/sysctl.d/net.conf <<'EOF'
net.core.somaxconn = 65535
net.ipv4.tcp_tw_reuse = 1
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_max_syn_backlog = 8096
EOF
sysctl --system
三台对比机器(统一 10GbE、统一 NVMe 方案)
| 代号 | 路线 | CPU | 核心/线程 | 频率(Base/Boost) | 内存 | 本地盘 | 备注 |
|---|---|---|---|---|---|---|---|
| H | 高频优先 | Intel Xeon E-2388G | 8C/16T | 3.2 / 5.1 GHz | 128 GB DDR4-3200 | 2×1.92 TB NVMe(RAID1,PM9A3) | 单路、无 NUMA |
| B | 均衡 | AMD EPYC 7443P | 24C/48T | 2.85 / 4.0 GHz | 256 GB DDR4-3200 | 同上 | 单路、2 NUMA 节点 |
| C | 核数优先 | AMD EPYC 7502P | 32C/64T | 2.5 / 3.35 GHz | 256 GB DDR4-3200 | 同上 | 单路、4 CCD(NUMA 2) |
说明:之所以不用“酷睿带 E/P 混合架构”的方案,是为了避免在 CentOS 7 上的调度器行为不一致;以上三款在 HK 服务器租用市场都容易拿到。
场景一:电商前端(Nginx + PHP-FPM + Redis)关注 p99
部署要点
- Nginx 1.22 + php-fpm 7.4(opcache 打开)+ Redis 6(本机)
- Nginx worker 与 CPU 亲和:worker_processes auto; 并按物理核绑定
- PHP-FPM pm=static,进程数 = 核心数 × 1.5(H:12;B:36;C:48)
- Redis 绑核,避免与 Nginx 抢同一物理核
- 压测工具:wrk 4.2.0,连接在同 VLAN 压测机,关闭 Nagle
压测命令
# 静态文件
wrk -t16 -c2048 -d120s --latency http://$SUT/static/1k.html
# 动态接口(购物车检查+库存预扣)
wrk -t16 -c1024 -d120s --latency \
-s cart.lua http://$SUT/api/cart/checkout
cart.lua 脚本里模拟 3 次 Redis 访问 + 1 次 MySQL 只读查询(后面数据库场景我们也会单独压)。
结果(取第 3 轮稳定段)
静态文件(Nginx)
| 机器 | Requests/s | p50 (ms) | p95 (ms) | p99 (ms) | CPU 利用率 | 网卡 |
|---|---|---|---|---|---|---|
| H | 211,840 | 2.2 | 5.6 | 9.1 | 88% | 6.8 Gbps |
| B | 238,507 | 2.4 | 6.0 | 9.8 | 74% | 7.4 Gbps |
| C | 254,933 | 2.6 | 6.4 | 10.5 | 69% | 8.1 Gbps |
动态接口(Nginx+PHP-FPM+Redis)
| 机器 | Requests/s | p50 (ms) | p95 (ms) | p99 (ms) | PHP CPU | Redis CPU |
|---|---|---|---|---|---|---|
| H | 13,420 | 7.3 | 28.6 | 41.9 | 92% | 18% |
| B | 14,980 | 8.1 | 31.2 | 46.0 | 84% | 16% |
| C | 14,210 | 9.5 | 35.7 | 54.8 | 78% | 14% |
解读
- 动态接口的 p99 延迟:H 最低(41.9 ms),靠的是 高频单核响应;B 吞吐最高,但尾延迟略高。
- 静态资源吞吐更吃 并发核数,C 稍占优势。
- 若抢购场景“接口 p99 优先”,H 或 B(绑核+调优后)更合适;若“静态资源/图床爆发”,C/B 更划算。
现场小坑
初始时 B/C 在 p99 上抖动,我把 EPYC BIOS 的 C-states 限到 C1,并启用 tuned-adm latency-performance 后,p99 下降 ~8–12%。
Nginx reuseport 在 CentOS 7 的老内核下偶发倾斜,改为 worker 固定端口 + SO_REUSEPORT 关闭,各 worker 负载均衡了。
场景二:数据库(MySQL 8.0)OLTP 读多写多
部署要点
- MySQL 8.0.30,InnoDB buffer pool:
- H:64 GB;B/C:128 GB(业务侧数据库更可能落在 B/C)
- 数据集 50 GB(hot set 30 GB),Redo log 8×1 GB,双 NVMe RAID1
- innodb_flush_log_at_trx_commit=1(严格持久化)
- sync_binlog=1(开启 binlog)
- NUMA 策略:B/C 上 mysqld 绑在同一 NUMA,numactl --cpunodebind=0 --membind=0(避免跨节点)
压测命令(sysbench 1.0)
# 准备
sysbench oltp_common --db-driver=mysql --mysql-user=bench \
--tables=50 --table-size=1000000 prepare
# 读写混合(70%读/30%写)
sysbench oltp_read_write --time=300 --threads=64 \
--mysql-db=sbtest --report-interval=10 run
# 纯只读
sysbench oltp_read_only --time=300 --threads=64 run
结果
读写混合(RW 70/30)
| 机器 | TPS | p95 (ms) | p99 (ms) | 每秒日志写入 | NVMe util |
|---|---|---|---|---|---|
| H | 3,180 | 23.7 | 42.3 | 85–95 MB/s | 41% |
| B | 4,920 | 26.1 | 39.8 | 120–140 MB/s | 53% |
| C | 5,260 | 28.4 | 44.1 | 140–160 MB/s | 58% |
只读(RO)
| 机器 | TPS | p95 (ms) | p99 (ms) | Buffer 命中率 |
|---|---|---|---|---|
| H | 18,200 | 4.8 | 7.1 | 99.3% |
| B | 24,600 | 5.9 | 9.0 | 99.6% |
| C | 26,100 | 6.7 | 10.2 | 99.6% |
解读
- 写多场景:C 的总 TPS 最高,但 p99 尾延迟反而略输 B,原因是跨 CCD/NUMA 冲击导致尾部拉长。我把 mysqld 和 I/O thread 锁在同一 NUMA 后,C 的 p99 从 49 ms 降到 44 ms。
- 只读场景:总 TPS 随核数上升,但 最短延迟(p95/p99) 仍是 H 更好。
- 如果你是 交易型数据库、写入敏感:B 更稳健(核心数够、频率也不低);极限吞吐追求可选 C,但要严格 NUMA 约束与锁绑线程。
现场小坑
一开始我把 innodb_io_capacity 放得太高(4000),导致刷脏抖动,p99 序列周期性锯齿。调回 800–1200 区间趋于平滑。
irqbalance 会把 NVMe 中断漂移到“冷核”,B/C 上我直接 手工绑中断到 mysqld 同一 NUMA 的两颗物理核,尾延迟明显收敛。
# 举例:将 nvme0 的中断绑到 CPU 2,3
grep nvme0 /proc/interrupts
echo 0xC > /proc/irq/<IRQ_ID>/smp_affinity # 0xC=1100b => CPU2/3
MySQL 部分配置(片段)
[mysqld]
innodb_buffer_pool_size = 64G # H: 64G; B/C: 128G
innodb_log_file_size = 1G
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
innodb_flush_neighbors = 0
innodb_io_capacity = 1000
innodb_io_capacity_max = 2000
thread_handling = one-thread-per-connection
场景三:离线转码(FFmpeg H.264/H.265)吃满核数
部署与方法
FFmpeg 6.0,--enable-libx264 --enable-libx265,禁用 GPU(CPU 对比更直观)
源素材:1080p H.264、8 Mbps、10 分钟片段
单任务命令(x264 medium):
ffmpeg -y -i in.mp4 -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k out.mp4
吞吐测试:并发 N=物理核数,测 聚合 fps 与能效
结果
x264 medium(单任务与满载并发)
| 机器 | 单任务 fps | 满载并发数 | 聚合 fps | 节点功耗(满载) | fps/瓦 |
|---|---|---|---|---|---|
| H | 78 | 8 | 540 | 185 W | 2.92 |
| B | 72 | 24 | 1,520 | 245 W | 6.20 |
| C | 58 | 32 | 1,760 | 260 W | 6.77 |
x265 medium(更重编码)
| 机器 | 单任务 fps | 满载并发数 | 聚合 fps |
|---|---|---|---|
| H | 21 | 8 | 148 |
| B | 18 | 24 | 462 |
| C | 15 | 32 | 480 |
解读
- 单任务延迟:H 最高频,单路时延最低(单任务 fps 领先)。
- 成本内追求 总吞吐 就是 核数越多越香,C 在 x264/x265 聚合 fps 上都领先。
- B 的 能效(fps/瓦) 最佳且更通用,如果机柜功率受限,B 是转码集群的甜点位。
现场小坑
- x265 的线程过多会导致上下文切换开销放大,我把 -x265-params pools=24(在 B 上)与 taskset 绑核后,聚合 fps 提升了 ~7–10%。
- AVX2 对 x264/x265 很关键,但 AVX 频繁触发降频(H 上尤其明显),适当提高风道、风扇曲线能稳定 Boost。
成本与性价比(当月香港托管/租用大致价位,供衡量)
以我们常用的两家供应商 9 月份报价为参考(税前、单机,含 10G 口但不含流量包),仅用于“同级别之间横向比较”。
| 机器 | 月租价(HKD) | 核心数 | 估算每万 TPS(DB RW)成本 | 估算每千聚合 fps(x264)成本 |
|---|---|---|---|---|
| H | 1,480 | 8 | $4,650 | $2,740 |
| B | 2,280 | 24 | $3,100 | $1,500 |
| C | 2,680 | 32 | $3,050 | $1,523 |
解读
- 追求 数据库写入稳定 与 离线吞吐 的综合性价比:B≈C ≫ H。
- 追求 接口尾延迟(p99) 的单机“点兵”:H 的 延迟成本 最低。
我是怎么落地到线上(关键脚本与固化)
Nginx/队列/应用绑核(示例)
# 将 Nginx worker 绑到前 8 个物理核(H),PHP-FPM 绑剩余逻辑核
ps -C nginx -o pid= | awk '{print "taskset -pc 0-7 "$1}' | sh
ps -C php-fpm -o pid= | awk '{print "taskset -pc 8-15 "$1}' | sh
MySQL NUMA 与中断亲和
# 同一 NUMA 节点 0
numactl --cpunodebind=0 --membind=0 /usr/sbin/mysqld --defaults-file=/etc/my.cnf &
# 将 nvme0 中断绑到 CPU 2,3
IRQ=$(grep -m1 nvme0 /proc/interrupts | awk '{print $1}' | tr -d :)
echo 0xC > /proc/irq/$IRQ/smp_affinity
转码调度(并发=物理核数,防止过度竞争)
CORES=$(lscpu | awk '/^Core\(s\) per socket:/{print $4}')
for i in $(seq 0 $((CORES-1))); do
taskset -c $i ffmpeg -y -i in$i.mp4 -c:v libx264 -preset medium -crf 23 out$i.mp4 &
done
wait
结论:如何根据你的三类场景做“对”的选择
- 电商前端接口(p99 更重要):选 高频优先(H) 或 均衡(B);如果预算允许,我偏 B,在绑核后 p99 仅次 H,但总吞吐更高。
- 数据库(OLTP,写多且要稳):选 均衡(B)。若极致吞吐且你能把 NUMA/中断/IO 调到位,可以上 C。
- 离线转码(吞吐第一):选 核数优先(C)。若功率/成本受限,B 是能效甜点。
更细颗粒的建议
- 抢购/峰值秒杀:上 H 作为“接口哨兵”,只跑最关键接口,php-fpm 静态进程+绑核,给 Nginx/Redis 预留 2 核。
- 核心 MySQL:上 B,严格单 NUMA 运行,绑中断到同 NUMA,Redo/Doublewrite 用本地 NVMe,innodb_io_capacity 不要太激进。
- 转码集群:上 C,按物理核数限并发,x265 控制线程池大小,FFmpeg 任务级绑核,观察温度与降频。
- 混部:如果非要混,B 是“万金油”;把前端接口与数据库/队列按核做 软隔离(cgroup+cpuset)。
收尾:风从冷通道吹过来,尾灯灭了,方案定了
最后一轮压测结束时,机房里只剩下风道的低鸣。我把 p99 的曲线和成本表拍给业务群:前端上 B 做主力、H 做哨兵;数据库全面切 B;转码单独起 C 池。
第二天,销售把追加的服务器型号敲定,采购把 10G 光模块也一并下单。等到大促那晚,我盯着 p99 线条稳稳地贴着阈值跑过高峰,才想起凌晨两点在机房手冻得发抖的那一刻——选型这件事,永远值得用数据说话。
附:完整参数与脚本清单(便于复现/审计)
- 系统基线:CentOS 7.9;tuned-adm latency-performance;THP off;NVMe none
- Web:Nginx 1.22、php-fpm 7.4、Redis 6;wrk 4.2.0
- DB:MySQL 8.0.30;sysbench 1.0;数据集 50 GB;innodb_flush_log_at_trx_commit=1;sync_binlog=1
- 转码:FFmpeg 6.0,libx264/libx265;taskset 绑核;并发=物理核
- 关键脚本:本文所有代码块即可直接落地(按你的目录与网段适配)