如果您发现运行时配置后性能下降,可能的原因包括:
-
线程数过多
- 症状:CPU 利用率低,上下文切换频繁
- 原因:I/O 密集型任务不需要大量工作线程
- 解决:减少工作线程数
-
线程栈过大
- 症状:内存占用高
- 原因:2MB × 线程数 = 过多内存
- 解决:使用默认栈大小(~1MB)
-
事件间隔过大
- 症状:响应延迟增加
- 原因:I/O 事件轮询不够频繁
- 解决:降低 event_interval
// I/O 密集型优化配置
let worker_threads = std::cmp::max(4, num_cpus::get() / 2);
tokio::runtime::Builder::new_multi_thread()
.worker_threads(worker_threads) // 8 线程 (16核系统)
.thread_name("sni-proxy-worker")
// 使用默认栈大小 (~1MB)
.enable_all()
.global_queue_interval(31)
.event_interval(31) // 降低到 31 提高响应
.build()?适用场景:
- ✅ I/O 密集型(流媒体代理)
- ✅ 长连接场景
- ✅ 大量并发连接
性能特点:
- 🔻 减少上下文切换
- 🔻 降低内存占用
- ⬆️ 提高 I/O 响应速度
| 配置 | 工作线程 | 栈大小 | event_interval | 适用场景 |
|---|---|---|---|---|
| 默认 | 核心数 | 默认 | 61 | 通用 |
| 旧配置 | 16 | 2MB | 61 | CPU 密集型 |
| 当前配置 | 8 | 默认 | 31 | I/O 密集型 ✅ |
| 极简配置 | 4 | 默认 | 31 | 低负载 |
| 配置 | 线程栈内存 | 说明 |
|---|---|---|
| 旧配置 | 16 × 2MB = 32MB | 过高 |
| 当前配置 | 8 × 1MB = 8MB | 适中 ✅ |
| 极简配置 | 4 × 1MB = 4MB | 最低 |
配置:
- 工作线程:CPU 核心数 / 2 (最少 4)
- 栈大小:默认
- 事件间隔:31
测试步骤:
# 1. 编译
cargo build --release
# 2. 启动服务
./target/release/sni-proxy config.json
# 3. 观察日志
🚀 Tokio 运行时配置:
工作线程数: 8 (CPU 核心: 16 物理, 16 逻辑)
线程栈大小: 默认 (~1MB)
事件间隔: 31 (I/O 响应优化)
# 4. 监控性能
# 观察 CPU 使用率
top -H -p $(pgrep sni-proxy)
# 观察上下文切换
pidstat -w -p $(pgrep sni-proxy) 1预期结果:
- ✅ CPU 利用率适中 (40-60%)
- ✅ 上下文切换减少
- ✅ 响应延迟降低
- ✅ 内存占用降低
如果当前配置仍然慢,尝试此配置:
修改 src/main.rs:
fn main() -> Result<()> {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(4) // 固定 4 线程
.thread_name("sni-proxy-worker")
.enable_all()
.global_queue_interval(31)
.event_interval(31)
.build()?;
runtime.block_on(async_main())
}适用场景:
- 并发连接 < 1000
- 单机部署
- 低负载环境
如果需要极致 I/O 性能:
修改 src/main.rs:
fn main() -> Result<()> {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(4)
.thread_name("sni-proxy-worker")
.enable_all()
.global_queue_interval(31)
.event_interval(1) // 最频繁的 I/O 轮询
.build()?;
runtime.block_on(async_main())
}警告:
⚠️ 增加系统调用开销⚠️ CPU 使用率会上升- ✅ 延迟最低
如果自定义配置导致问题,使用默认配置:
修改 src/main.rs:
#[tokio::main]
async fn async_main() -> Result<()> {
// ... 原有代码
}
fn main() -> Result<()> {
// 简单启动(使用默认运行时)
async_main()
}或者保持自定义运行时但使用默认参数:
fn main() -> Result<()> {
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?;
runtime.block_on(async_main())
}1. 连接测试
# 使用 wrk 测试 HTTP 代理性能
wrk -t4 -c100 -d30s https://example.com
# 使用 ab 测试
ab -n 10000 -c 100 https://example.com/2. CPU 分析
# 实时监控 CPU 使用
top -H -p $(pgrep sni-proxy)
# 查看线程 CPU 分布
ps -Lf -p $(pgrep sni-proxy) -o pid,tid,psr,pcpu,comm3. 上下文切换分析
# 监控上下文切换(越低越好)
pidstat -w -p $(pgrep sni-proxy) 1
# 预期值:
# cswch/s < 1000 (非常好)
# cswch/s < 5000 (良好)
# cswch/s > 10000 (需要优化)4. 延迟测试
# 使用 ping 测试延迟
time curl -I https://example.com
# 查看连接建立时间
curl -w "@curl-format.txt" -o /dev/null -s https://example.com
# curl-format.txt 内容:
# time_namelookup: %{time_namelookup}\n
# time_connect: %{time_connect}\n
# time_starttransfer: %{time_starttransfer}\n
# time_total: %{time_total}\n作用:异步任务执行线程池大小
选择指南:
I/O 密集型(流媒体代理):
- 推荐: CPU 核心数 / 2 到 1/4
- 范围: 4 - 8 线程
- 原因: I/O 操作主要等待,不需要大量线程
CPU 密集型(加密、压缩):
- 推荐: CPU 核心数
- 范围: 8 - 16 线程
- 原因: 需要充分利用 CPU 计算能力
混合负载:
- 推荐: CPU 核心数 × 0.75
- 范围: 6 - 12 线程
- 原因: 平衡 I/O 和 CPU 使用
测试方法:
# 测试不同线程数的性能
for threads in 4 8 12 16; do
echo "测试 $threads 线程"
# 修改配置,重启服务,运行基准测试
# 记录吞吐量和延迟
done作用:轮询 I/O 事件的频率
参数说明:
event_interval = 1:
- 每次循环都轮询 epoll/kqueue
- 延迟最低,但 CPU 开销最高
- 适合低延迟要求
event_interval = 31:
- 每 31 次任务轮询一次
- 延迟适中,CPU 开销适中
- 推荐用于流媒体代理 ✅
event_interval = 61:
- 每 61 次任务轮询一次
- 延迟稍高,CPU 开销最低
- 适合低负载环境
权衡:
- 值越小:延迟越低,但 CPU 使用率越高
- 值越大:CPU 效率越高,但延迟越高
作用:工作窃取调度器的公平性
参数说明:
global_queue_interval = 10:
- 任务分配更公平
- 适合任务执行时间差异大的场景
global_queue_interval = 31: (默认)
- 平衡公平性和性能
- 推荐值 ✅
global_queue_interval = 100:
- 性能最高
- 可能导致任务分配不均
建议:保持默认值 31
检查项:
# 1. 确认使用 release 构建
cargo build --release
./target/release/sni-proxy config.json
# 2. 检查 CPU 使用率
top -p $(pgrep sni-proxy)
# 如果 CPU 很低(< 20%),减少线程数
# 如果 CPU 很高(> 80%),增加线程数
# 3. 检查上下文切换
pidstat -w -p $(pgrep sni-proxy) 1
# 如果 cswch/s > 10000,减少线程数
# 4. 检查内存
ps aux | grep sni-proxy
# 检查 RSS(内存)是否过高可能原因:
- event_interval 过大
- 线程数过少
- 全局队列间隔不合适
解决方案:
// 降低 event_interval
.event_interval(1) // 最激进
// 或者增加线程数
.worker_threads(num_cpus::get())可能原因:
- event_interval 过小
- 线程数过多
解决方案:
// 增加 event_interval
.event_interval(61)
// 减少线程数
.worker_threads(4)tokio::runtime::Builder::new_multi_thread()
.worker_threads(4)
.enable_all()
.event_interval(31)
.build()?let worker_threads = std::cmp::max(4, num_cpus::get() / 2);
tokio::runtime::Builder::new_multi_thread()
.worker_threads(worker_threads)
.enable_all()
.event_interval(31)
.build()?tokio::runtime::Builder::new_multi_thread()
.worker_threads(num_cpus::get())
.enable_all()
.event_interval(31)
.build()?最后更新: 2025-12-04 版本: 1.1.0