第11章:性能调优
第11章:性能调优
11.1 性能调优概述
Varnish 的性能调优涉及多个层面:操作系统内核参数、Varnish 运行时参数、VCL 配置优化和架构优化。
11.1.1 性能指标
| 指标 | 说明 | 目标值 |
|---|
| 缓存命中率 | Cache Hit / Total Requests | > 80% |
| 响应延迟 | P95 响应时间 | < 50ms |
| 并发连接数 | 同时处理的连接数 | 根据业务 |
| 后端负载 | 后端请求率 | 最小化 |
| 内存使用 | 缓存对象占用内存 | < 80% 可用内存 |
| 线程利用率 | 活跃线程 / 最大线程 | < 80% |
11.1.2 性能测试工具
# wrk - HTTP 基准测试工具
wrk -t12 -c400 -d30s http://localhost:6081/
# ab - Apache Bench
ab -n 10000 -c 100 http://localhost:6081/
# hey - HTTP 负载生成器
hey -z 30s -c 100 http://localhost:6081/
# siege - HTTP 负载测试
siege -c 100 -t 30S http://localhost:6081/
11.2 操作系统内核参数
11.2.1 Linux 内核调优
# /etc/sysctl.d/99-varnish.conf
# 文件描述符限制
fs.file-max = 131072
fs.nr_open = 131072
# TCP 参数优化
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_max_tw_buckets = 2000000
# TCP 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 连接跟踪
net.netfilter.nf_conntrack_max = 1048576
# 内存
vm.swappiness = 10
vm.max_map_count = 262144
# 应用内核参数
sudo sysctl -p /etc/sysctl.d/99-varnish.conf
11.2.2 系统限制
# /etc/security/limits.d/varnish.conf
varnish soft nofile 131072
varnish hard nofile 131072
varnish soft nproc 65535
varnish hard nproc 65535
# memlock 限制(用于大页面内存)
varnish soft memlock 85983232
varnish hard memlock 85983232
11.2.3 systemd 服务限制
# /etc/systemd/system/varnish.service.d/limits.conf
[Service]
LimitNOFILE=131072
LimitNPROC=65535
LimitMEMLOCK=85983232
LimitAS=infinity
LimitFSIZE=infinity
LimitDATA=infinity
LimitSTACK=infinity
LimitCORE=infinity
LimitRSS=infinity
# 重新加载 systemd
sudo systemctl daemon-reload
sudo systemctl restart varnish
11.3 线程池调优
11.3.1 线程池参数
# 查看当前线程池配置
varnishadm param.show thread_pool_min
varnishadm param.show thread_pool_max
varnishadm param.show thread_pools
varnishadm param.show thread_pool_timeout
# 设置线程池参数
varnishadm param.set thread_pools 2
varnishadm param.set thread_pool_min 10
varnishadm param.set thread_pool_max 500
varnishadm param.set thread_pool_timeout 120
11.3.2 线程池参数详解
| 参数 | 说明 | 推荐值 |
|---|
thread_pools | 线程池数量 | 2(等于 CPU 核数一半) |
thread_pool_min | 每池最小线程数 | 5-10 |
thread_pool_max | 每池最大线程数 | 500 |
thread_pool_timeout | 空闲线程超时(秒) | 120 |
thread_queue_limit | 队列等待限制 | 20 |
thread_stats_rate | 统计更新频率 | 10 |
11.3.3 线程监控
# 查看线程状态
varnishstat -1 | grep -E "MAIN.threads|MAIN.sess"
# 关键指标
# MAIN.threads - 当前活跃线程数
# MAIN.threads_created - 已创建线程总数
# MAIN.threads_failed - 创建失败的线程数
# MAIN.threads_limited - 因限制被拒绝的请求数
# MAIN.thread_queue_len - 等待线程的请求数
# 告警阈值
# threads_limited > 0 - 线程池已满,需要增加 thread_pool_max
# thread_queue_len > 10 - 请求排队严重,需要增加线程
11.3.4 线程池优化建议
# VCL 中监控线程状态
sub vcl_recv {
# 记录请求排队时间
set req.http.X-Queue-Start = now;
}
sub vcl_deliver {
# 添加线程信息到响应头(调试用)
# 注意:生产环境不要暴露这些信息
}
11.4 内存管理
11.4.1 存储引擎配置
# 内存存储(推荐)
varnishd -s malloc,256m
varnishd -s malloc,1G
varnishd -s malloc,8G
# 文件存储
varnishd -s file,/var/lib/varnish/varnish_storage.bin,1G
# 多存储引擎
varnishd -s Transient=malloc,256m -s default=file,/var/lib/varnish/storage,50G
11.4.2 内存使用计算
# 估算内存使用
# 每个缓存对象的开销:
# - 对象头部:约 256-512 字节
# - 响应头部:约 1-4 KB
# - 响应体:实际大小
# 示例计算:
# 假设平均对象大小:10 KB
# 可用内存:8 GB
# 可缓存对象数:8 GB / 10 KB = 819,200 个对象
# 查看实际内存使用
varnishstat -1 | grep -E "SMA.n_object|SMA.g_bytes|SMA.g_space"
# SMA.n_object - 缓存对象数量
# SMA.g_bytes - 已使用字节数
# SMA.g_space - 可用字节数
11.4.3 内存碎片优化
# 使用 jemalloc 替代默认 malloc
# 编译时启用 jemalloc
./configure --with-jemalloc
# 或在启动时预加载
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so
varnishd ...
11.4.4 Transient 存储
# 不缓存的对象使用 Transient 存储
sub vcl_backend_response {
if (beresp.uncacheable) {
# 不缓存的对象使用独立的 Transient 存储
set beresp.storage = storage.Transient;
}
}
11.5 连接数调优
11.5.1 连接相关参数
# 查看连接参数
varnishadm param.show sess_timeout
varnishadm param.show sess_workspace
varnishadm param.show timeout_idle
varnishadm param.show timeout_linger
# 设置连接参数
varnishadm param.set sess_timeout 5s
varnishadm param.set timeout_idle 5s
varnishadm param.set timeout_linger 0.05
11.5.2 连接参数详解
| 参数 | 说明 | 推荐值 |
|---|
sess_timeout | 会话超时 | 5s |
timeout_idle | 空闲超时 | 5s |
timeout_linger | 等待新请求时间 | 0.05s |
sess_workspace | 会话工作空间 | 256k |
shm_workspace | 共享内存工作空间 | 8k |
11.5.3 HTTP/2 调优
# HTTP/2 参数
varnishadm param.show h2_max_header_list_size
varnishadm param.show h2_max_concurrent_streams
varnishadm param.show h2_initial_window_size
# 设置
varnishadm param.set h2_max_concurrent_streams 100
varnishadm param.set h2_initial_window_size 65535
11.6 工作空间调优
11.6.1 工作空间参数
# 工作空间是每个请求/后端连接的私有内存区域
# 查看工作空间参数
varnishadm param.show workspace_client
varnishadm param.show workspace_backend
varnishadm param.show workspace_session
varnishadm param.show workspace_thread
# 设置工作空间
varnishadm param.set workspace_client 256k
varnishadm param.set workspace_backend 256k
varnishadm param.set workspace_session 256k
varnishadm param.set workspace_thread 2k
11.6.2 工作空间溢出检测
# 监控工作空间溢出
varnishstat -1 | grep -E "MAIN.ws_backend_overflow|MAIN.ws_client_overflow|MAIN.ws_thread_overflow"
# 如果有溢出,增加对应的工作空间
# ws_backend_overflow > 0 → 增加 workspace_backend
# ws_client_overflow > 0 → 增加 workspace_client
11.6.3 工作空间优化
# 工作空间使用建议
sub vcl_recv {
# 如果有很多自定义头部,需要更大的工作空间
# workspace_client 默认 64k,建议 256k
}
sub vcl_backend_response {
# 如果后端返回很多头部,需要更大的工作空间
# workspace_backend 默认 64k,建议 256k
}
11.7 缓存大小优化
11.7.1 缓存容量规划
# 估算所需缓存大小
# 1. 分析访问模式
# 获取平均对象大小
varnishstat -1 | grep -E "SMA.g_bytes|SMA.n_object"
# 2. 确定缓存目标
# - 缓存所有活跃内容
# - 保持合理命中率(>80%)
# 3. 计算公式
# 缓存大小 = 平均对象大小 × 目标对象数 × 1.2(冗余)
11.7.2 LRU 策略
# Varnish 使用近似 LRU(Least Recently Used)策略
# 当缓存满时,淘汰最久未使用的对象
# 监控 LRU 淘汰
varnishstat -1 | grep -E "MAIN.n_lru_nuked"
# n_lru_nuked > 0 表示有对象被淘汰
# 考虑增加缓存大小
11.8 VCL 性能优化
11.8.1 VCL 执行效率
sub vcl_recv {
# 优化建议 1:尽早返回
# 对于不需要缓存的请求,尽早返回 pass
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# 优化建议 2:减少正则匹配
# 使用字符串前缀判断代替正则
if (req.url ~ "^/api/") {
# 使用字符串操作
set req.http.X-Path = regsub(req.url, "^/api/", "");
}
# 优化建议 3:合并正则
# 不好的写法
# if (req.url ~ "\.css$") { ... }
# if (req.url ~ "\.js$") { ... }
# 好的写法
if (req.url ~ "\.(css|js)$") { ... }
# 优化建议 4:避免在热路径上做复杂操作
# 将不常变化的逻辑放在 vcl_init 或编译时
}
sub vcl_hash {
# 优化建议 5:最小化 hash 数据
# 只 hash 必要的信息
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
}
# 避免添加不必要的 hash 数据
return (lookup);
}
11.8.2 后端连接复用
sub vcl_backend_fetch {
# 启用后端连接复用(默认启用)
# Varnish 会自动复用后端连接
# 设置合理的超时
set bereq.connect_timeout = 5s;
set bereq.first_byte_timeout = 30s;
set bereq.between_bytes_timeout = 10s;
}
11.9 性能基准测试
11.9.1 基准测试脚本
#!/bin/bash
# benchmark.sh - Varnish 性能基准测试
URL="http://localhost:6081/"
DURATION=60
CONNECTIONS="50 100 200 500"
THREADS=4
echo "=== Varnish Benchmark ==="
echo "URL: $URL"
echo "Duration: ${DURATION}s"
echo ""
for CONN in $CONNECTIONS; do
echo "--- Connections: $CONN ---"
wrk -t$THREADS -c$CONN -d${DURATION}s $URL | grep -E "Requests/sec|Latency|Transfer/sec"
echo ""
sleep 5
done
echo "=== Statistics ==="
varnishstat -1 | grep -E "MAIN.cache_hit|MAIN.cache_miss|MAIN.client_req|MAIN.threads"
11.9.2 性能对比
# 对比不同配置的性能
# 测试 1:默认配置
varnishd -a :6081 -s malloc,256m -f default.vcl
wrk -t4 -c200 -d30s http://localhost:6081/
# 测试 2:优化配置
varnishd -a :6081 -s malloc,1G \
-p thread_pool_min=10 \
-p thread_pool_max=500 \
-p thread_pools=2 \
-p workspace_client=256k \
-p workspace_backend=256k \
-f optimized.vcl
wrk -t4 -c200 -d30s http://localhost:6081/
11.10 注意事项
重要
- 性能调优需要逐步进行,一次只调整一个参数
- 每次调整后都需要进行基准测试验证效果
- 内存不是越多越好,要预留足够的系统内存
- 线程数过多会导致上下文切换开销,适度即可
- 缓存命中率是最重要的指标,命中率低时优化 VCL 配置比调整参数更有效
- 生产环境修改参数前先在测试环境验证
- 定期监控性能指标,及时发现瓶颈
11.11 扩展阅读