负载均衡 #
一、负载均衡概述 #
1.1 什么是负载均衡 #
负载均衡是将请求分发到多个后端服务器的技术,用于:
- 提高可用性
- 提升性能
- 实现扩展性
- 故障转移
1.2 Varnish负载均衡架构 #
text
┌─────────────────────────────────────────────────────────┐
│ Varnish 负载均衡架构 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ │
│ │ Client │ │
│ └────┬────┘ │
│ │ │
│ ┌────▼────┐ │
│ │ Varnish │ │
│ │ Load │ │
│ │ Balancer│ │
│ └────┬────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │
│ │Server 1 │ │Server 2 │ │Server 3 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
1.3 支持的调度算法 #
| 算法 | 说明 | 适用场景 |
|---|---|---|
| round_robin | 轮询 | 服务器性能相近 |
| fallback | 故障转移 | 主备模式 |
| hash | 哈希 | 会话保持 |
| random | 随机 | 简单分发 |
二、directors模块 #
2.1 导入模块 #
vcl
import directors;
2.2 定义后端 #
vcl
backend server1 {
.host = "192.168.1.10";
.port = "80";
}
backend server2 {
.host = "192.168.1.11";
.port = "80";
}
backend server3 {
.host = "192.168.1.12";
.port = "80";
}
2.3 初始化负载均衡器 #
vcl
sub vcl_init {
# 创建负载均衡器
new cluster = directors.round_robin();
cluster.add_backend(server1);
cluster.add_backend(server2);
cluster.add_backend(server3);
}
2.4 使用负载均衡器 #
vcl
sub vcl_recv {
set req.backend_hint = cluster.backend();
}
三、轮询调度 #
3.1 基本配置 #
vcl
import directors;
backend server1 { .host = "192.168.1.10"; .port = "80"; }
backend server2 { .host = "192.168.1.11"; .port = "80"; }
backend server3 { .host = "192.168.1.12"; .port = "80"; }
sub vcl_init {
new cluster = directors.round_robin();
cluster.add_backend(server1);
cluster.add_backend(server2);
cluster.add_backend(server3);
}
sub vcl_recv {
set req.backend_hint = cluster.backend();
}
3.2 工作原理 #
text
请求1 ──► Server 1
请求2 ──► Server 2
请求3 ──► Server 3
请求4 ──► Server 1
请求5 ──► Server 2
...
3.3 加权轮询 #
vcl
sub vcl_init {
new cluster = directors.round_robin();
# 高性能服务器添加多次
cluster.add_backend(server1);
cluster.add_backend(server1);
cluster.add_backend(server2);
cluster.add_backend(server3);
}
四、故障转移 #
4.1 基本配置 #
vcl
import directors;
backend primary {
.host = "192.168.1.10";
.port = "80";
}
backend secondary {
.host = "192.168.1.11";
.port = "80";
}
sub vcl_init {
new cluster = directors.fallback();
cluster.add_backend(primary);
cluster.add_backend(secondary);
}
sub vcl_recv {
set req.backend_hint = cluster.backend();
}
4.2 工作原理 #
text
正常情况:
请求 ──► Primary Server
Primary故障:
请求 ──► Secondary Server
Primary恢复:
请求 ──► Primary Server
4.3 多级故障转移 #
vcl
sub vcl_init {
new cluster = directors.fallback();
cluster.add_backend(primary);
cluster.add_backend(secondary);
cluster.add_backend(tertiary);
}
五、哈希调度 #
5.1 基本配置 #
vcl
import directors;
backend server1 { .host = "192.168.1.10"; .port = "80"; }
backend server2 { .host = "192.168.1.11"; .port = "80"; }
backend server3 { .host = "192.168.1.12"; .port = "80"; }
sub vcl_init {
new cluster = directors.hash();
cluster.add_backend(server1, 1.0);
cluster.add_backend(server2, 1.0);
cluster.add_backend(server3, 1.0);
}
sub vcl_recv {
# 基于URL哈希
set req.backend_hint = cluster.backend(req.url);
}
5.2 工作原理 #
text
URL /page1 ──► Hash(URL) ──► Server 1
URL /page2 ──► Hash(URL) ──► Server 2
URL /page1 ──► Hash(URL) ──► Server 1 (相同URL总是到同一服务器)
5.3 会话保持 #
vcl
sub vcl_recv {
# 基于Cookie会话保持
if (req.http.Cookie ~ "session_id") {
set req.backend_hint = cluster.backend(
regsub(req.http.Cookie, ".*session_id=([^;]+).*", "\1")
);
} else {
set req.backend_hint = cluster.backend(req.url);
}
}
5.4 基于IP哈希 #
vcl
sub vcl_recv {
# 基于客户端IP哈希
set req.backend_hint = cluster.backend(client.ip);
}
5.5 权重配置 #
vcl
sub vcl_init {
new cluster = directors.hash();
# 权重比例 2:1:1
cluster.add_backend(server1, 2.0);
cluster.add_backend(server2, 1.0);
cluster.add_backend(server3, 1.0);
}
六、随机调度 #
6.1 基本配置 #
vcl
import directors;
backend server1 { .host = "192.168.1.10"; .port = "80"; }
backend server2 { .host = "192.168.1.11"; .port = "80"; }
backend server3 { .host = "192.168.1.12"; .port = "80"; }
sub vcl_init {
new cluster = directors.random();
cluster.add_backend(server1, 1.0);
cluster.add_backend(server2, 1.0);
cluster.add_backend(server3, 1.0);
}
sub vcl_recv {
set req.backend_hint = cluster.backend();
}
6.2 加权随机 #
vcl
sub vcl_init {
new cluster = directors.random();
# 权重比例 3:2:1
cluster.add_backend(server1, 3.0);
cluster.add_backend(server2, 2.0);
cluster.add_backend(server3, 1.0);
}
七、健康检查集成 #
7.1 后端健康检查 #
vcl
probe healthcheck {
.url = "/healthcheck";
.timeout = 2s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
backend server1 {
.host = "192.168.1.10";
.port = "80";
.probe = healthcheck;
}
backend server2 {
.host = "192.168.1.11";
.port = "80";
.probe = healthcheck;
}
backend server3 {
.host = "192.168.1.12";
.port = "80";
.probe = healthcheck;
}
7.2 自动剔除故障服务器 #
负载均衡器会自动检测后端健康状态,不健康的后端会被自动剔除:
vcl
import directors;
sub vcl_init {
new cluster = directors.round_robin();
cluster.add_backend(server1);
cluster.add_backend(server2);
cluster.add_backend(server3);
}
# 当server2不健康时,请求会自动分发到server1和server3
八、动态后端管理 #
8.1 运行时添加后端 #
vcl
import dynamic;
sub vcl_init {
new d = dynamic.director(
port = "80",
ttl = 10m
);
}
sub vcl_recv {
# 动态选择后端
if (req.http.X-Backend-Host) {
set req.backend_hint = d.backend(req.http.X-Backend-Host);
}
}
8.2 基于DNS发现 #
vcl
import dynamic;
sub vcl_init {
new d = dynamic.director(
port = "80",
ttl = 30s
);
}
sub vcl_recv {
# 使用DNS名称
set req.backend_hint = d.backend("backend.example.com");
}
九、高级配置 #
9.1 多集群配置 #
vcl
import directors;
# Web服务器集群
backend web1 { .host = "192.168.1.10"; .port = "80"; }
backend web2 { .host = "192.168.1.11"; .port = "80"; }
# API服务器集群
backend api1 { .host = "192.168.2.10"; .port = "8080"; }
backend api2 { .host = "192.168.2.11"; .port = "8080"; }
sub vcl_init {
new web_cluster = directors.round_robin();
web_cluster.add_backend(web1);
web_cluster.add_backend(web2);
new api_cluster = directors.round_robin();
api_cluster.add_backend(api1);
api_cluster.add_backend(api2);
}
sub vcl_recv {
if (req.url ~ "^/api/") {
set req.backend_hint = api_cluster.backend();
} else {
set req.backend_hint = web_cluster.backend();
}
}
9.2 基于内容类型分发 #
vcl
sub vcl_recv {
if (req.url ~ "\.(css|js|png|gif|jpg|jpeg)$") {
set req.backend_hint = static_cluster.backend();
} elseif (req.url ~ "^/api/") {
set req.backend_hint = api_cluster.backend();
} else {
set req.backend_hint = web_cluster.backend();
}
}
9.3 基于地理位置分发 #
vcl
import geoip;
sub vcl_recv {
if (geoip.country_code(client.ip) == "CN") {
set req.backend_hint = china_cluster.backend();
} elseif (geoip.country_code(client.ip) == "US") {
set req.backend_hint = us_cluster.backend();
} else {
set req.backend_hint = global_cluster.backend();
}
}
9.4 A/B测试 #
vcl
sub vcl_recv {
if (req.http.Cookie ~ "variant=b") {
set req.backend_hint = variant_b.backend();
} else {
set req.backend_hint = variant_a.backend();
}
}
十、故障处理 #
10.1 重试机制 #
vcl
sub vcl_backend_response {
# 后端错误时重试
if (beresp.status >= 500 && bereq.retries < 3) {
return (retry);
}
}
10.2 超时处理 #
vcl
sub vcl_backend_error {
# 记录错误
std.log("Backend error: " + bereq.url);
# 返回错误页面
set beresp.status = 503;
set beresp.http.Content-Type = "text/html";
synthetic({"<!DOCTYPE html>
<html>
<head><title>Service Unavailable</title></head>
<body>
<h1>503 Service Unavailable</h1>
<p>Please try again later.</p>
</body>
</html>"});
return (deliver);
}
10.3 熔断机制 #
vcl
import vsthrottle;
sub vcl_recv {
# 检查后端是否熔断
if (vsthrottle.is_denied("backend_" + req.backend_hint, 10, 10s)) {
return (synth(503, "Backend circuit breaker open"));
}
}
sub vcl_backend_response {
if (beresp.status >= 500) {
# 记录失败
vsthrottle.add("backend_" + bereq.backend, 1);
}
}
十一、监控与管理 #
11.1 查看后端状态 #
bash
# 查看所有后端
varnishadm backend.list
# 输出示例
name ref probe health
server1 1 5/5 healthy
server2 1 5/5 healthy
server3 1 3/5 sick
11.2 后端统计 #
bash
# 查看后端连接统计
varnishstat -1 -f VBE.*
# 查看特定后端
varnishstat -1 -f VBE.server1.*
11.3 手动管理后端 #
bash
# 设置后端状态
varnishadm backend.set_health server1 sick
varnishadm backend.set_health server1 healthy
varnishadm backend.set_health server1 auto
11.4 监控脚本 #
bash
#!/bin/bash
# lb_monitor.sh
echo "=== Load Balancer Status ==="
echo ""
echo "Backend Health:"
varnishadm backend.list
echo ""
echo "Backend Connections:"
varnishstat -1 -f VBE.*.conn
echo ""
echo "Backend Requests:"
varnishstat -1 -f VBE.*.req
echo ""
echo "Backend Failures:"
varnishstat -1 -f VBE.*.fail
十二、完整配置示例 #
vcl
vcl 4.1;
import directors;
import std;
# 健康检查配置
probe healthcheck {
.url = "/healthcheck";
.timeout = 2s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
# Web服务器后端
backend web1 {
.host = "192.168.1.10";
.port = "80";
.probe = healthcheck;
.max_connections = 500;
}
backend web2 {
.host = "192.168.1.11";
.port = "80";
.probe = healthcheck;
.max_connections = 500;
}
backend web3 {
.host = "192.168.1.12";
.port = "80";
.probe = healthcheck;
.max_connections = 500;
}
# API服务器后端
backend api1 {
.host = "192.168.2.10";
.port = "8080";
.probe = healthcheck;
.max_connections = 300;
}
backend api2 {
.host = "192.168.2.11";
.port = "8080";
.probe = healthcheck;
.max_connections = 300;
}
# 初始化负载均衡器
sub vcl_init {
# Web集群 - 轮询
new web_cluster = directors.round_robin();
web_cluster.add_backend(web1);
web_cluster.add_backend(web2);
web_cluster.add_backend(web3);
# API集群 - 哈希(会话保持)
new api_cluster = directors.hash();
api_cluster.add_backend(api1, 1.0);
api_cluster.add_backend(api2, 1.0);
}
# 请求处理
sub vcl_recv {
# 根据URL选择集群
if (req.url ~ "^/api/") {
# API请求 - 基于会话保持
if (req.http.Cookie ~ "session_id") {
set req.backend_hint = api_cluster.backend(
regsub(req.http.Cookie, ".*session_id=([^;]+).*", "\1")
);
} else {
set req.backend_hint = api_cluster.backend(req.url);
}
} else {
# Web请求 - 轮询
set req.backend_hint = web_cluster.backend();
}
# 添加客户端IP
set bereq.http.X-Forwarded-For = client.ip;
}
# 后端错误处理
sub vcl_backend_response {
# 错误重试
if (beresp.status >= 500 && bereq.retries < 3) {
return (retry);
}
}
sub vcl_backend_error {
set beresp.status = 503;
set beresp.http.Content-Type = "text/html; charset=utf-8";
synthetic({"<!DOCTYPE html>
<html>
<head><title>Service Unavailable</title></head>
<body>
<h1>503 Service Unavailable</h1>
<p>The server is temporarily unavailable.</p>
</body>
</html>"});
return (deliver);
}
十三、总结 #
本章我们学习了:
- 负载均衡概述:概念、架构、算法
- directors模块:导入和基本使用
- 轮询调度:round_robin配置
- 故障转移:fallback配置
- 哈希调度:hash配置、会话保持
- 随机调度:random配置
- 健康检查集成:自动剔除故障服务器
- 动态后端:运行时管理
- 高级配置:多集群、A/B测试
- 故障处理:重试、超时、熔断
- 监控管理:状态查看、手动管理
掌握负载均衡后,让我们进入下一章,学习缓存规则配置!
最后更新:2026-03-28