Docker Swarm 和 Varnish 持久 TCP 连接 (VIP) 的负载平衡

Docker Swarm 和 Varnish 持久 TCP 连接 (VIP) 的负载平衡

我在 40 个工作程序前面运行了一个 Varnish HTTP 缓存。这些工作程序在两个相同的 Docker 节点(node-1node-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 连接。

  1. 如果这个理论有意义的话,我该如何证实它?
  2. 有哪些可能的解决方法?

我正在考虑在 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 中执行此操作。

相关内容