上一篇 下一篇 分享链接 返回 返回顶部

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

发布人:Minchunlin 发布时间:2025-09-29 10:52 阅读量:171


凌晨两点,部署在香港葵涌机房的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!
目录结构
全文