Tengo una aplicación Laravel ejecutándose en producción y hay algunas API que se usan mucho. Algo estaba creando un cuello de botella y solía bloquear nuestros servidores (3 con Load Balancer). Después de optimizar los conceptos básicos en Laravel, configuración de almacenamiento en caché, rutas, datos, etc., incluso resolver todos los problemas n+1, todavía teníamos problemas en las horas pico. Alguien sugirió que ejecutemos strace en uno de los trabajadores de nginx para ver qué está sucediendo a nivel del sistema, así lo hicimos, y lo que es bastante interesante, hay muchas llamadas al sistema redundantes en las que nginx intenta encontrar archivos cuando se llama a las API:
Parte del rastro:
240498 stat("/var/www/html/myProject/current/public/APIRequest/3d4f7518e04e9", 0x7ffc7ee6ff70) = -1 ENOENT (No such file or directory)
240498 stat("/var/www/html/myProject/current/public/APIRequest/3d4f7518e04e9", 0x7ffc7ee6ff70) = -1 ENOENT (No such file or directory)
240498 lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
240498 lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
240498 lstat("/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
240498 lstat("/var/www/html/myProject", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0
240498 lstat("/var/www/html/myProject/current", {st_mode=S_IFLNK|0777, st_size=48, ...}) = 0
240498 readlink("/var/www/html/myProject/current", "/var/www/html/myProject/release"..., 4095) = 48
240498 lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
240498 lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
240498 lstat("/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
240498 lstat("/var/www/html/myProject", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0
240498 lstat("/var/www/html/myProject/releases", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
240498 lstat("/var/www/html/myProject/releases/20201202085755", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
240498 lstat("/var/www/html/myProject/releases/20201202085755/public", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
Ahora se llama a la API con el ID 3d4f7518e04e9
en este caso e intenta recorrer los directorios para encontrar ese archivo. Pero no es un archivo, es una API. Ejecutamos strace durante menos de 30 segundos y tenemos 5.000 llamadas de este tipo que no tienen sentido para mí.
Entonces, ¿son necesarias estas llamadas? No lo creo, pero dime si me equivoco. Y si estoy en lo cierto, ¿cómo puedo configurar mejor mi nginx para que estas llamadas puedan "captarse a tiempo" y resolverse adecuadamente? Cualquier idea es bienvenida. :)
PD: También hemos probado Apache con una configuración similar, aparece el mismo problema en strace.
Editar: ¿Simplemente necesito algún tipo de directiva de ubicación en la configuración de mi sitio para resolver esto? Estoy usando la configuración básica de nginx de los documentos oficiales.https://laravel.com/docs/8.x/deployment#nginxcon algunas adiciones más como:
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
location ~ /\.(?!well-known).* {
deny all;
}
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 4 16k;
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;
EDITAR:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
Tengo archivos de prueba como lo sugirió Danila Vershinin en una respuesta
Respuesta1
Parece que estás lidiando con try_files
un problema de rendimiento. Puede deshacerse de stat
las llamadas innecesarias al sistemaeliminandotry_files
desde su configuración.
La try_files
directiva proporciona un modelo sencillo y agradable para crear un sitio web compatible con SEO.
Sin embargo, la desventaja de esta simplicidad viene con un costo adicional de stat
llamadas innecesarias al sistema.
Como sabes que, por ejemplo, todas /api/
las URL deben enrutarse a través de tu PHP, no es necesario verificar la existencia de ningún archivo allí y puedes enrutarlas a través de tu archivo de arranque Laravel incondicionalmente, por ejemplo:
location /api/ {
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
fastcgi_pass unix:/var/run/php-fpm/example.com.sock;
}
Además, en general, desea tener información de caché NGINX sobre la existencia de archivos/directorios. Esto se puede lograr a través deopen_file_cache.