我们最近遇到了无法解释的延迟问题,这反映在我们的 AWS 设置的 ELB 延迟指标上。
我们的设置包括 ELB 后面的 3 台 EC2 c1.medium 机器(每台都运行 NGINX,与机器上的 uWSGI 处理程序通信)。
现在,我们的流量在早上和晚上出现高峰,但这并不能解释我们所看到的情况,即在流量高峰期间出现 10 秒的延迟峰值。
我们的 NGINX 日志和 uWSGI 统计数据显示,我们没有对任何请求进行排队,并且响应时间稳定在 500 毫秒以下。
ELB监听8443端口并传输到8080
NGINX 在每个 EC2 上都有以下配置:
worker_processes 2;
pid /var/run/nginx.pid;
events {
worker_connections 4000;
multi_accept on;
use epoll;
}
http {
server {
reset_timedout_connection on;
access_log off;
listen 8080;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3031;
}
}
}
我想知道是否有人经历过类似的事情或者可以提供解释。
谢谢你..
我不确定它是否在某个地方有记录,但我们已经使用 ELB 有一段时间了。本质上,ELB 是您要进行负载平衡的实例之前的 EC2 实例,我们的理解是,当您的 ELB 开始经历更多流量时,Amazon 会执行一些魔法,将该 ELB 实例从 c1.medium 转变为 m1.xlarge。
因此,当您开始看到峰值时,亚马逊可能会在较小的 ELB 实例与较大的 ELB 实例之间进行一些转换,并且您会看到这些延迟。
客户不知道亚马逊内部发生了什么,所以据你所知,他们可能会在高峰期遇到大流量,并且他们的负载均衡器会发疯。
您可能可以通过过度配置来避免这些延迟,但谁愿意花更多的钱。
如果您有时间和资源,我会推荐以下几件事:
在您的环境(一些大型实例)前面设置一个 haproxy 实例并以这种方式监控您的流量。 Haproxy 有一个命令行(或 Web)实用程序,可让您查看统计信息。当然,您还需要监控实例的 CPU 和内存等信息。
您可能无法在生产中执行此操作,在这种情况下,您将不得不运行
test traffic
。我建议使用类似 loader.io 的东西。另一种选择是尝试将部分流量发送到 haproxy 实例,也许使用 GSLB(如果您的 DNS 提供商支持)客户端由于移动连接不完整而未能在空闲超时过去之前发送整个请求标头和正文,
AWS Classic Load Balancer 将返回
504 Gateway Timeout
。这是非常违反直觉的,因为 5xx
HTTP 错误应该始终表明服务器/后端出现问题,而不是客户端。查看 ELB 的
Latency
指标并将其设置为
Maximum
而不是
Average
,您会注意到最长的请求花费的时间与 ELB 空闲超时大致相同,这意味着请求超时。但是,超时的可能不是您的后端 - 可能是客户端。客户端可能无法在空闲超时过去之前发送整个请求标头和正文。
这意味着,如果您的 ELB 为连接到不完整网络的移动设备提供服务,您的
Average Latency
指标将受到这些设备发送的较慢请求的影响,并且
ELB 5xxs
指标将报告发送给未能发送请求的客户端的 5xx 错误及时。据我所知,
AWS 官方文档上没有任何记录。文档总是指出后端本身的超时问题,而不是客户端的连接不完整。
您可以使用此 Node.js 脚本在您自己的 ELB 上进行测试,该脚本创建一个示例 POST 请求,其Content-Length
比实际发送的正文长 500 个字符,迫使 ELB 等待客户端发送更多数据, 并不可避免地导致它关闭与
504 Gateway Timeout
:的连接
const https = require('https');
const postData = JSON.stringify({
name: 'John Doe',
age: 30
});
const options = {
hostname: 'YOUR_ELB_HOSTNAME', // Replace with your ELB hostname, no https://
port: 443,
path: '/sample-path',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData) + 500
}
};
const req = https.request(options, (res) => {
let data = '';
// Collect response data
res.on('data', (chunk) => {
data += chunk;
});
// End of response
res.on('end', () => {
console.log('Status code: ' + res.statusCode + ' ' + res.statusMessage);
});
});
// Handle errors
req.on('error', (e) => {
console.error(`Problem with request: ${e.message}`);
});
// Write the data to the request body
req.write(postData);
// End the request
req.end();
将 YOUR_ELB_HOSTNAME
替换为您自己的 ELB 主机名。当运行此脚本并等待空闲超时过去时,控制台最终将打印
504 GATEWAY_TIMEOUT
状态代码,并且 AWS 控制台中的
Latency
和
ELB 5xxs
图表确实会将请求计为
5xx
并提高 ELB 的整体
Average Latency
。似乎没有任何办法解决这个问题 - 除了迁移到应用程序负载均衡器(ALB 将挂起套接字而不是将请求计为
504
),或者使用以下命令阻止来自 ELB 的相应客户端 IP AWS VPC ACL。如果您正在监控
ELB 5xxs
指标,您可能需要将警报阈值增加到 > 1,这样每次来自不完整的移动设备的请求超时时您都不会收到警报。至于
Latency
- 您可能需要切换到
IQM
(四分位数)而不是
Average
,这样客户端超时就不会影响您的 ELB
Latency
整体。