Visão geral
Meu aplicativo da Web permite que os usuários carreguem arquivos armazenados em s3 por meio de meus servidores. Quando um usuário solicita um arquivo, meu servidor da Web o recupera de s3 e o envia para o cliente.
Recentemente, implantei um balanceador de carga, configurando minha configuração atual da seguinte maneira:
Nomomento,tenhoapenasumúnicoservidordaWebparasimplificaradepuração.
ProblemaInicial
Depoisdeimplantarobalanceadordecarga,noteiqueosdownloadsdearquivosmaiores(qualquercoisamaiorquecercade4MB)falhariamcomotempolimitedogateway504após60segundos.
Euolheiparaologdeerrosdonginxdobalanceadordecargadositeevialgumasentradascomo:
[error]11770#11770:*40upstreamtimedout(110:Connectiontimedout)whilereadingresponseheaderfromupstream,client:XXXX,...
QuandoeuolheinologdeerrodonginxdoservidordaWebparaosite,vientradassemelhantes:
[error]6632#6632:*41upstreamtimedout(110:Connectiontimedout)whilereadingresponseheaderfromupstream,client:...[error]6632#6632:*85upstreamtimedout(110:Connectiontimedout)whilereadingresponseheaderfromupstream,client:...[error]7163#7163:*41recv()failed(104:Connectionresetbypeer)whilereadingresponseheaderfromupstream,client:...[error]7505#7505:*41recv()failed(104:Connectionresetbypeer)whilereadingresponseheaderfromupstream,client:...[error]7505#7505:*91recv()failed(104:Connectionresetbypeer)whilereadingresponseheaderfromupstream,client:....
Eolhandooslogsdeerrosdophp-fpmnoservidorwebqueeutinha:
WARNING:[poolwww]child3011,script'/home/forge/XXX.com/public/index.php'(request:"GET /index.php") execution timed out (64.950545 sec), terminating
WARNING: [pool www] child 3011 exited on signal 15 (SIGTERM) after 1140.059968 seconds from start
WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
WARNING: [pool www] child 4260, script '/home/forge/XXX.com/public/index.php' (request: "GET /index.php") execution timed out (68.171099 sec), terminating
WARNING: [pool www] child 4260 exited on signal 15 (SIGTERM) after 160.005837 seconds from start
NOTICE: [pool www] child 4271 started
Eu coloquei isso para baixo para não ter meus tempos de execução de php e timeouts de conexão nginx muito baixos, então eu os aumentei fazendo o seguinte:
- No balanceador de carga:
- Adicione
proxy_read_timeout 600s;
ao /etc/nginx/nginx.conf
- No servidor da web:
- Na configuração do site nginx, adicionei
fastcgi_read_timeout 600;
ao bloco de localização .php.
- Adicionamos
max_execution_time = 600
e default_socket_timeout = 600
à configuração do php-fpm.
- Adicionada
request_terminate_timeout = 300
ao /etc/php/7.0/fpm/pool.d/www.conf
Isso corrigiu meu problema inicial até certo ponto, já que agora posso baixar arquivos maiores (testados até 25 MB).
Próximo problema - downloads lentos
Após a configuração acima, posso fazer o download dos arquivos sem tempo limite, mas o tempo de download é muito longo (~ 300 segundos) e o próprio download é lento (menor preocupação).
O fluxo para baixar um arquivo é o seguinte:
- Cliente clica em um link que atinge meu servidor
- Meu servidor da Web acessa o banco de dados e obtém informações como o nome do arquivo em hash e o caminho para o servidor de banco de dados.
- O servidor da web recupera o arquivo da S3.
- O servidor da Web responde com o arquivo como um download para a solicitação inicial:
Para referência, a função que está sendo executada no servidor da Web para fazer isso é:
public function show($projectID, $documentID, $revisionID, $fileID)
{
$fileEntry = File::find($fileID);
$path = $fileEntry->path();
$file = Storage::get($path);
$size = Storage::size($path);
return Response::make($file, 200)
->header('Content-Type', $fileEntry->mime)
->header('Content-Disposition', 'attachment; filename="' . $fileEntry->original_filename . '"')
->header('Content-Length:', $size);
}
Eu entendo que estou lidando com os arquivos em dobro e no futuro mudarei para redirecionamentos de URL s3 assinados, mas há outras partes do aplicativo onde isso não será prático (pegar uma coleção de arquivos, zipar e enviar para o cliente) e, portanto, gostaria de ganhar algum entendimento.
Qual poderia ser a causa desse problema? Não acredito que tenha encontrado esse problema antes de implantar o balanceador de carga.
Se eu baixar o arquivo diretamente do s3, os tempos de download são uma fração do tempo geral quando chego através do meu servidor, portanto, não acredito que o tratamento duplo seja o problema. Poderia ser o buffer ou o tamanho da memória relacionado?
Informações adicionais:
- Laravel forge usado para provisionar e os servidores.
- encerramento SSL no balanceador de carga
- aplicativo da web do Laravel
- Linode está tudo hospedado no data center de Cingapura
- A região S3 é Sydney
- Problemas foram observados em tráfego extremamente baixo (até 1 cliente)