我们正在构建一个允许从云端调用本地 API 的平台,为此我们使用 WCF 中继,这实际上是适合我们的服务,因为我们需要动态创建中继(我们有一个载入 API它负责验证客户许可,并在许可有效的情况下在 Azure 中创建中继,以使云 API 和本地 API 之间的通信成为可能)。
目前,我们的 QA 团队正在进行负载测试,以了解有多少流量支持该平台,在测试期间,我们的 QA 团队在运行来自 JMeter 的 50 个并发请求的测试时检测到了一个奇怪的行为。
基本上,在这种情况下(50 个并发请求),一些请求由于 502 Bad Gateway 响应而失败,这些响应来自中继,因为内容类型是 XML。
502 Bad Gateway 响应告诉侦听器在允许的时间间隔内没有接受连接,但奇怪的是,一旦我们收到 502 Bad Gateway 响应,就没有更多请求到达侦听器(本地 API),使通信再次起作用的唯一方法是关闭侦听器并重新启动它。
据我所知,WCF 中继支持负载均衡,使用随机策略选择负责处理请求的侦听器,我在 Github repo 中找到了一个属于 WCF 中继服务的线程,其中描述负载均衡算法如下:
- 获取发送者请求的地址的所有已知负载平衡侦听器列表的本地副本(这来自每 500 毫秒更新一次的缓存)。
- 如果侦听器列表为空,并且我们没有完全刷新侦听器列表一次,则强制刷新端点的已知负载平衡侦听器列表。
- 如果侦听器列表为空,则向发送者返回异常并停止。
- 在潜在听众列表中选择一个随机索引。
- 尝试与选定的侦听器会合。
- 如果该会合成功,则停止。
- 如果与所选侦听器的集合尝试在 10 秒内未成功,则从要尝试的侦听器列表中删除所选侦听器。
- 如果超过 60 秒,则向发件人返回异常。
- 转到第 2 步。
如果算法以上述方式工作,那么默认行为对 DoS 攻击非常敏感,因为一旦集合尝试失败,侦听器将从侦听器列表中删除以尝试,这是一个非常糟糕的主意,因为只有使通信再次正常工作的方法是重新连接侦听器,在我们的例子中,这意味着用户手动操作,因为我们将 WCF 服务托管在 Windows 服务中(如果集合尝试失败,用户应该重新启动 Windows 服务)。
有趣的是,我们正在将“ConnectionStatusBehaviour”应用于端点以记录任何连接问题,并且我们在日志中看不到任何奇怪的东西,显然,服务保持连接/在线,并且在天蓝色监视器中,侦听器保持连接为出色地。
当集合点尝试不成功时,有一些方法可以配置不同的行为?。
我们当前的WCF配置如下:
实际绑定配置(WebHttpRelayBinding)
- 安全模式 = 传输
- RelayClientAuthenticationType = RelayAccessToken
- IsDynamic = 假
- UseDefaultProxy = false
- OpenTimeout = 10 秒
- 关闭超时 = 10 秒
- 发送超时 = 10 秒
- ReceiveTimeout = TimeSpan.MaxValue
实际服务节流行为
- MaxConcurrentCalls = 160
- MaxConcurrentInstances = 1000
- 最大并发会话数 = 1160
实际 Wcf 服务行为
- InstanceContextMode = PerCall
- 并发模式 = 单
客户端
WCF 中继是使用 HttpClient 从 AspNetCore 2.2 应用程序调用的,因为中继地址是在运行时发现的(在这种情况下我们不能使用 WCF 代理)。
AspNetCore 应用程序托管在 Azure 中。
听众
部署在 Azure 中的虚拟机上 系统连接模式使用值 ConnectivityMode.Https 进行配置