强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第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 注意事项

重要

  1. 性能调优需要逐步进行,一次只调整一个参数
  2. 每次调整后都需要进行基准测试验证效果
  3. 内存不是越多越好,要预留足够的系统内存
  4. 线程数过多会导致上下文切换开销,适度即可
  5. 缓存命中率是最重要的指标,命中率低时优化 VCL 配置比调整参数更有效
  6. 生产环境修改参数前先在测试环境验证
  7. 定期监控性能指标,及时发现瓶颈

11.11 扩展阅读