我在 40 个工作程序前面运行了一个 Varnish HTTP 缓存。这些工作程序在两个相同的 Docker 节点(node-1
和node-2
,每个节点 20 个)上运行,作为唯一的服务(web_workers
)。我们使用默认的 Docker Swarm endpoint_mode
,即循环负载平衡。因此,Varnish 将请求转发到唯一的后端主机名(据我所知,= Docker Swarm 虚拟 IP)。
不久前,我注意到节点接收到的请求负载不平等:node-1
处理的请求比多 4 倍node-2
。
Varnish 使用长寿命的持久 TCP 连接与后端连接,并node-2
在 之后启动node-1
。我怀疑负载差异可以通过node-1
首先启动的事实来解释,而 Docker Swarm 简单的循环负载平衡算法在node-2
启动之前刚刚为其分配了持久 TCP 连接,现在看来这种不平衡会持续存在,因为 Varnish 使用长寿命的 TCP 连接。
- 如果这个理论有意义的话,我该如何证实它?
- 有哪些可能的解决方法?
我正在考虑在 Varnish 端禁用 TCP 连接重用,但这可能会导致严重的性能下降(有待测试)。另一个选择是不使用唯一的 Docker 服务,而是每个物理节点都有一个。我也可以在 Docker 服务更新后立即重新启动 Varnish 实例,但这是一个敏感的基础设施,我不想重新启动。欢迎提出任何想法!
编辑:
VCL文件的后端配置部分:
backend origin {
.between_bytes_timeout = 5s;
.connect_timeout = 1s;
.first_byte_timeout = 5s;
.host = "web_origin";
.host_header = "web_origin";
.max_connections = 200;
.port = "8080";
}
sub vcl_init {
new origin_director = directors.round_robin();
origin_director.add_backend(origin);
}
答案1
您需要了解的是,Varnish 中的 DNS 解析是在编译团队中完成的。这意味着,当您的 VCL 文件加载时,Varnish 将解析主机名并坚持使用 IP 地址。
如果web_origin
引用多个 IP 地址,Varnish 将仅选择一个。当再次加载 VCL 时(由于重新启动或显式 VCL 重新加载),可能会使用另一个 IP。
如果要在 VCL 中执行循环负载平衡,则至少需要 2 个原始服务器。以下是示例:
vcl 4.1;
import directors;
backend origin1 {
.between_bytes_timeout = 5s;
.connect_timeout = 1s;
.first_byte_timeout = 5s;
.host = "web_origin";
.host_header = "web_origin1";
.max_connections = 200;
.port = "8080";
}
backend origin2 {
.between_bytes_timeout = 5s;
.connect_timeout = 1s;
.first_byte_timeout = 5s;
.host = "web_origin";
.host_header = "web_origin2";
.max_connections = 200;
.port = "8080";
}
sub vcl_init {
new origin_director = directors.round_robin();
origin_director.add_backend(origin1);
origin_director.add_backend(origin2);
}
sub vcl_recv {
set req.backend_hint = origin_director.backend();
}
如果web_origin
主机名仅指向单个 IP 并且您想要继续在 VIP 级别进行负载平衡,则您可以考虑减少[backend_idle_timeout][1]
运行时参数的值。
但是,如果您想对负载平衡有更多的控制,最好在 Varnish 中执行此操作。