You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

YARP反向代理轮询负载均衡失效问题排查求助

YARP RoundRobin负载均衡在Docker Swarm中失效的排查与解决

可能原因及对应方案

1. DNS解析缓存导致端点固定

Docker Swarm的服务域名(如mytestwebapp)会解析到多个容器IP,但YARP默认依赖的HttpClient会缓存DNS解析结果,不会主动刷新。这会导致YARP一直使用第一次解析到的容器IP,无法轮询其他节点。

解决方法:

  • 配置YARP通过自定义IDestinationProvider动态获取Docker Swarm后端端点;
  • 或修改HttpClient的DNS缓存与连接复用策略,强制定期刷新:
    services.AddHttpClient()
        .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
        {
            PooledConnectionLifetime = TimeSpan.FromSeconds(30), // 定期回收连接
            DnsRefreshTimeout = TimeSpan.FromSeconds(10) // 缩短DNS缓存有效期
        });
    

2. 负载均衡策略配置错误

检查YARP配置,确认RoundRobin策略已正确绑定到目标集群:

正确配置示例(JSON):

{
  "ReverseProxy": {
    "Routes": {
      "myRoute": {
        "ClusterId": "myCluster",
        "Match": {
          "Path": "{**catch-all}"
        }
      }
    },
    "Clusters": {
      "myCluster": {
        "LoadBalancingPolicy": "RoundRobin",
        "Destinations": {
          "mytestwebapp": {
            "Address": "http://mytestwebapp"
          }
        }
      }
    }
  }
}
  • 确保LoadBalancingPolicy字段明确设置为RoundRobin;
  • 代码配置时需确认集群绑定正确的负载均衡器:
    services.AddReverseProxy()
        .LoadFromConfig(Configuration.GetSection("ReverseProxy"))
        .ConfigureCluster("myCluster", cluster =>
        {
            cluster.LoadBalancingPolicy = "RoundRobin";
        });
    

3. 长连接复用导致请求绑定同一容器

客户端与YARP、YARP与后端容器之间的Keep-Alive长连接,会让同一客户端的后续请求复用已建立的TCP连接,直接命中同一容器,绕过负载均衡策略。

解决方法:

  • 优先调整连接池生命周期(如前文PooledConnectionLifetime配置),让连接定期断开并重新选择节点;
  • 临时排查可禁用Keep-Alive(不推荐生产环境,会降低性能):
    "Clusters": {
      "myCluster": {
        "LoadBalancingPolicy": "RoundRobin",
        "HttpClient": {
          "DisableKeepAlive": true
        },
        "Destinations": {
          "mytestwebapp": {
            "Address": "http://mytestwebapp"
          }
        }
      }
    }
    

4. Docker Swarm端点未被动态感知

YARP默认不会主动监听Docker Swarm的服务端点变化,容器扩容/缩容后无法自动更新目标列表。

解决方法:

  • 实现自定义IDestinationProvider,通过Docker Swarm API(/services/mytestwebapp/tasks)定期获取所有运行中容器的IP和端口,更新YARP目标列表:
    public class SwarmDestinationProvider : IDestinationProvider
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly string _serviceName;
        private IEnumerable<Destination> _destinations;
    
        public SwarmDestinationProvider(IHttpClientFactory httpClientFactory, IConfiguration configuration)
        {
            _httpClientFactory = httpClientFactory;
            _serviceName = configuration["Swarm:ServiceName"];
            _ = RefreshDestinationsAsync();
        }
    
        public IEnumerable<Destination> GetDestinations() => _destinations;
    
        private async Task RefreshDestinationsAsync()
        {
            while (true)
            {
                var client = _httpClientFactory.CreateClient();
                var tasks = await client.GetFromJsonAsync<List<SwarmTask>>($"http://localhost:2375/services/{_serviceName}/tasks");
                _destinations = tasks.Select(t => new Destination
                {
                    Address = $"http://{t.Status.ContainerStatus.IPAddress}:{t.Spec.ContainerSpec.Ports[0].PublishedPort}"
                }).ToList();
                await Task.Delay(TimeSpan.FromSeconds(30));
            }
        }
    }
    
    // Startup注册
    services.AddSingleton<IDestinationProvider, SwarmDestinationProvider>();
    

快速排查步骤

  1. 在YARP容器内执行nslookup mytestwebapp,验证DNS是否返回多个容器IP;
  2. 开启YARP调试日志,确认负载均衡器初始化状态及每次请求的目标地址;
  3. 使用不同客户端发起请求(如多终端curl),观察是否命中不同容器(同一客户端因长连接绑定属于正常现象)。

内容的提问来源于stack exchange,提问作者brando

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:17:33