香港服务器的高频小核 vs 低频多核全面对比(Web/缓存/计算)— 各项参数、调优细节与踩坑记录,给你可复现实验与明确选型建议

凌晨两点,部署在香港葵涌机房的CDN回源突然抖了一下,业务侧同事在群里问我:到底要不要把高频小核的机器换成低频多核?
我盯着监控:静态资源 95P 百分位抖了 20ms,Redis 的 p99 偶尔窜到 1.8ms。再靠“感觉”拍脑袋不行了。于是我干脆把两套物理机都拉进来,搭了一套一比一可复现实验,把 Web、缓存、计算三类负载都跑一遍,从配置—>调优—>压测—>定位问题—>给出选型建议,把话说死:到底选谁。
测试对象与硬件参数
注:以下为我在香港机房的两类常见现货方案;价格为我当时的月租报价(仅作对比基准)。
| 方案 | CPU | 核心/线程 | 基频/睿频 | 内存 | 磁盘 | 网卡 | 机型特征 | 价格 (USD/月) |
|---|---|---|---|---|---|---|---|---|
| A:高频小核 | Intel Xeon E-2288G | 8C/16T | 3.7 / 5.0 GHz | 64GB DDR4-2666 | 2×1.92TB NVMe (RAID1) | 10GbE (Intel X710) | 高频、单核强、核数少 | 199 |
| B:低频多核 | Dual Xeon Silver 4214 | 24C/48T | 2.2 / 3.2 GHz | 128GB DDR4-2400 | 2×1.92TB NVMe (RAID1) | 10GbE (Mellanox ConnectX-4) | 多核、NUMA、频率低 | 379 |
- 机房/网络:香港本地节点,跨境回源;ToR 25G 上联,客户端压测端(新加坡云)到机房 RTT ≈ 35–38ms。
- 操作系统:CentOS 7.9(内核 3.10.0-1160 系 backport),与我的生产环境一致。
固件与BIOS关键项(两机一致,能配的都配了):
- 关闭 C1E/C6 深度睡眠,打开 Turbo Boost;
- 固定高性能电源策略;
- 打开 SR-IOV,NIC 配 RSS,多队列;
- NUMA(B 方案)保持默认,两颗 CPU 各一 NUMA 节点。
软件栈与统一调优
基本内核与系统调优(两机统一)
/etc/sysctl.d/90-tuning.conf:
# 网络队列与连接跟踪
net.core.netdev_max_backlog = 250000
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# 文件描述符
fs.file-max = 2000000
# RMem/WMem
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
/etc/security/limits.d/90-nofile.conf:
* soft nofile 1048576
* hard nofile 1048576
- tuned:throughput-performance;irqbalance:开启;
- 时钟源:默认 tsc,NTP 校时,稳定。
Web 压测栈
- Nginx 1.22(TLS1.3 + reuseport),静态与反代分虚拟主机;
- 动态:Go 1.20 自写 echo + JSON/模板渲染(CPU型),gogc=100;
- 压测:wrk2(固定 RPS 模式),并发 C = 64 / 256 / 1024。
Nginx 关键配置(简化):
worker_processes auto;
worker_rlimit_nofile 1048576;
events { use epoll; worker_connections 65535; }
http {
sendfile on; tcp_nopush on; tcp_nodelay on; aio threads=default;
server_tokens off;
keepalive_timeout 15;
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers on;
upstream app {
server 127.0.0.1:8080;
keepalive 256;
}
server {
listen 443 ssl reuseport;
location /api {
proxy_pass http://app;
}
location /static/ { root /data/www; }
}
}
Go 动态服务(CPU 重一些的 JSON 拼装):
http.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) {
// 模拟业务逻辑:JSON组装 + 小量哈希计算
// ... 省略部分 ...
w.Header().Set("Content-Type", "application/json")
w.Write(bytes)
})
log.Fatal(http.ListenAndServe(":8080", nil))
缓存压测栈(Redis)
- Redis 6.2,AOF 关闭、RDB 关闭(纯内存 QPS 对比);
- 单实例测试 + 分片多实例(每实例绑定 CPU);
- 压测:redis-benchmark -t get,set -n 10000000 -q -P 32 -c 512(单实例),分片时并行执行。
Redis 核心配置:
bind 0.0.0.0
protected-mode no
maxmemory 48gb
maxmemory-policy allkeys-lru
tcp-keepalive 60
# CentOS 7 建议关闭 THP
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
CPU 绑定(示例):
# A: 8 实例时每实例绑 1-2 线程;B: 可跑到 16-24 实例
taskset -c 0 redis-server /etc/redis/redis-0.conf
taskset -c 1 redis-server /etc/redis/redis-1.conf
# ...
计算型压测栈
- ffmpeg 4.4,x264 medium 预设,1080p -> 1080p 重编码;
- gzip/zstd 批量压缩(CPU 压测),多进程并行。
方法论:如何对齐、如何测
- 升温:先用 stress-ng 把 CPU 升温 10 分钟,避免睿频初期虚高。
- 固定负载:wrk2 固定目标 RPS,逐步加压直到 p99 过阈。
- 观测:htop、pidstat -t、perf top、sar -n DEV 1 看瓶颈位置。
- 网络:网卡队列绑核(RPS/RFS 开启),确认软中断不集中在 0 号核。
- NUMA(仅B):单进程绑单 NUMA(numactl --cpunodebind=0 --membind=0),对比跨节点内存访问抖动。
- 重复三轮:每轮 15 分钟,取中位数,去掉异常峰。
一、Web 场景结果
1) 静态资源(Nginx/TLS)
资源 32KB,开启 TLS1.3,HTTP/1.1,keepalive=on
| 并发 | 目标 RPS | A 高频小核 p50/p99 (ms) | B 低频多核 p50/p99 (ms) | 达成情况 |
|---|---|---|---|---|
| 64 | 50,000 | 6.2 / 12.8 | 6.6 / 13.5 | 两者均稳 |
| 256 | 120,000 | 7.8 / 18.9 | 8.3 / 20.4 | 两者均稳 |
| 1024 | 180,000 | 11.6 / 29.7 | 12.9 / 33.8 | A 略优 |
观察:TLS 握手与内核态开销偏单核敏感,A 在高并发下 p99 更低;B 的软中断在少数核上偏热,需调 RSS 队列与 irqbalance。
2) 动态接口(Go/CPU型)
JSON 渲染 + 轻哈希,内存/IO 压力小,CPU 为主
| 并发 | 目标 RPS | A p50/p99 (ms) | B p50/p99 (ms) | 达成情况 |
|---|---|---|---|---|
| 64 | 25,000 | 9.3 / 21.2 | 10.8 / 24.7 | A 更稳 |
| 256 | 40,000 | 17.6 / 42.9 | 16.1 / 39.8 | B 反超 |
| 1024 | 60,000 | 29.4 / 78.3 | 26.8 / 71.5 | B 明显更稳 |
结论(Web):
- 静态/混合场景:A 稍占优,尤其在 TLS/请求调度对单核敏感时;
- 重动态/高并发:B 凭核量在 C=256 以上开始反超。
二、缓存场景(Redis)
| 指标 | A 高频小核 | B 低频多核 |
|---|---|---|
| GET QPS(p99<1ms) | 1.25M | 0.96M |
| SET QPS(p99<1.5ms) | 1.05M | 0.82M |
解释:Redis 单线程对单核频率非常敏感,A 领先明显。
多实例分片(无跨实例事务)
- A:8 实例(每实例 1 线程,绑 8 个物理核)
- B:16 实例(每实例 1 线程,绑 16 个物理核,分跨两 NUMA)
| 指标 | A(8 实例) | B(16 实例) |
|---|---|---|
| 聚合 GET QPS | 7.2M | 8.0M |
| 聚合 SET QPS | 6.1M | 6.8M |
| p99(GET) | 1.3ms | 1.1ms(NUMA 绑对后) |
踩坑:B 初期 p99 波动 1.6–2.3ms,原因是跨 NUMA 内存访问;加 numactl --cpunodebind --membind 后显著收敛。
结论(缓存):
- 单实例/单线程:A 更强。
- 多实例/可分片:B 通过数量碾压,总吞吐与p99都能更好,但前提是NUMA 绑定正确。
三、计算型(转码/压缩)
ffmpeg x264(1080p、medium)
| 指标 | A 高频小核 | B 低频多核 |
|---|---|---|
| 平均帧速(fps) | 42 | 87 |
| CPU 利用率 | 98% | 92% |
| p99 帧耗时 | 38ms | 22ms |
批量压缩(zstd -3,多进程并行 16/32)
| 并发进程 | A 吞吐(MB/s) | B 吞吐(MB/s) |
|---|---|---|
| 16 | 980 | 1,720 |
| 32 | 1,120(已接近饱和) | 2,850 |
结论(计算):B 硬核优势,非常明显。
成本与“单位性能成本”
为了让决策更直观,我算了两类代表性指标的单位性能成本(越低越好):
| 场景 | 指标 | A($199/月) | B($379/月) | 谁更划算 |
|---|---|---|---|---|
| 静态 Web | 180k RPS 稳态 | $1.11 / 100k RPS | $2.10 / 100k RPS | A |
| 动态 Web | 60k RPS 稳态 | $3.32 / 10k RPS | $2.52 / 10k RPS | B(并发高) |
| Redis 单实例 | 1M GET QPS | $0.16 / 100k QPS | $0.39 / 100k QPS | A |
| Redis 分片 8–16 实例 | 8.0M GET QPS | $2.76 / 1M QPS | $2.37 / 1M QPS | B |
| 转码 fps | 平均 fps | $4.74 / 10 fps | $4.35 / 10 fps | B |
关键问题与现场解法(踩坑清单)
B 方案 NUMA 抖动
现象:Redis 多实例 p99 抖高。
解决:实例与内存同绑 NUMA:
numactl --cpunodebind=0 --membind=0 redis-server ...
numactl --cpunodebind=1 --membind=1 redis-server ...
同时给 NIC 队列分布到对应 NUMA 的 CPU(ethtool -l / -L + RSS)。
软中断集中(两方案都可能发生)
- 现象:X710/ConnectX-4 中断集中 0 号核,导致单核热。
- 解决:irqbalance 开启 + smp_affinity_list 手动分配关键 IRQ 到多核。
透明大页 THP 干扰 Redis(CentOS 7)
解决:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
文件句柄与 TIME_WAIT
现象:wrk2 高并发时 EMFILE、端口耗尽。
解决:nofile=1,048,576、ip_local_port_range 拉大、tcp_tw_reuse=1。
睿频与温度回落(A 方案特征明显)
解决:充分预热 + 机柜风道优化;必要时降低单核峰值换稳定性。
容器化的调度干扰
现象:k8s 默认 CFS share 导致关键进程被“切碎”。
解决:为 Redis/ffmpeg 设置 Guaranteed QoS、cpuManagerPolicy=static,为关键进程做 CPU 集绑。
复现实验:一键跑通脚本片段
安装压测工具与基础包
yum groupinstall -y "Development Tools"
yum install -y epel-release jemalloc numactl htop perf sysstat git
# wrk2
git clone https://github.com/giltene/wrk2 && cd wrk2 && make
cp wrk /usr/local/bin/wrk2
Nginx 编译要点(TLS/HTTP2 可选)
# 省略源码下载...
./configure --with-file-aio --with-threads --with-http_ssl_module --with-http_v2_module
make -j && make install
静态/动态压测命令
# 静态
wrk2 -t8 -c256 -d120s -R120000 https://$HOST/static/32k.bin
# 动态
wrk2 -t16 -c1024 -d120s -R60000 https://$HOST/api/user
Redis 单实例/分片
# 单实例
redis-benchmark -h $HOST -p 6379 -n 10000000 -q -P 32 -c 512 get
# 分片(并行对 16 个端口)
for p in {7000..7015}; do
redis-benchmark -h $HOST -p $p -n 2000000 -q -P 32 -c 512 get &
done
wait
ffmpeg 转码
ffmpeg -y -threads 0 -i in_1080p.mp4 -c:v libx264 -preset medium -crf 23 out.mp4
决策矩阵:如何选?
| 业务特点 | 延迟敏感 | 吞吐需求 | 架构可分片 | 成本压力 | 建议 |
|---|---|---|---|---|---|
| 静态+轻动态 Web | 高 | 中 | 可 | 高 | A 高频小核(单核强、TLS 好) |
| 重动态 Web(高并发) | 中 | 高 | 可 | 中 | B 低频多核(核量顶上去) |
| Redis 单实例 | 高 | 中 | 不可 | 高 | A |
| Redis 可分片 | 中 | 很高 | 可 | 中 | B(NUMA 绑对) |
| 转码/压缩/批处理 | 中 | 很高 | 可 | 中 | B |
| 混合场景 | 高 | 高 | 视情况 | 中 | A+B 混搭:入口/A,后端/B |
经验法则:
- 低延迟/单线程热点 → 选 A。
- 海量并发/可水平切分 → 选 B。
- 入口边缘层(TLS、WAF、反代)更偏 A;业务/队列/计算层更偏 B。
- 有预算就混搭:A 把“门口”撑稳,B 在后场堆吞吐。
- 收尾:把凌晨两点变成可以复制的白天
那天夜里,我把最终结论丢进群里:入口层继续用高频小核,后端计算与分片缓存切到低频多核。第二天白天,同样的流程我又跑了一遍,把脚本和参数交给同事,不靠人记忆,靠可复现实验。
香港机房的风依旧冷,但心里热乎了:我们不是在赌运气,而是在管控确定性。
- Web 静态/TLS:A 微优、性价比高。
- Web 高并发动态:B 更稳,吞吐更高。
- Redis:单实例 A 胜,多实例分片 B 胜(注意 NUMA)。
- 计算型:B 碾压。
- 预算够:A 做入口,B 扛后场。
附:运维清单(可直接抄)
- BIOS:关 C-states 深睡、开 Turbo,高性能电源策略。
- 内核:tuned=throughput-performance,irqbalance=on,调 sysctl 与 nofile。
- NIC:开 RSS,多队列,中断绑核。
- Redis:关 THP,单实例看频率,多实例做 NUMA 同绑。
- Nginx:reuseport、合理 keepalive、TLS1.3。
- k8s:关键组件做 Guaranteed QoS + CPU 固定。
- 压测:预热 → 固定 RPS → 三轮中值 → 记得观测 p99!