
У меня есть приложение Laravel, работающее в production, и есть несколько API, которые используют много. Что-то создавало узкое место, и это останавливало наши серверы (3 с Load Balancer). После оптимизации основ в Laravel, кэширования конфигурации, маршрутов, данных и т. д., даже устранения всех проблем n+1, у нас все еще были проблемы в часы пик. Кто-то предложил запустить strace на одном из рабочих процессов nginx, чтобы посмотреть, что происходит на системном уровне, что мы и сделали, и, что интересно, есть много избыточных системных вызовов, где nginx пытается найти файлы при вызове API:
Часть следа:
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
Теперь API вызывается с идентификатором 3d4f7518e04e9
в этом случае, и он пытается пройтись по каталогам, чтобы найти этот файл. Но это не файл, это API. Мы запустили strace менее чем на 30 секунд, и у нас есть 5 тыс. таких вызовов, которые для меня не имеют смысла.
Итак, нужны ли эти вызовы? Я так не думаю, но скажите мне, если я не прав. И если я прав, как мне лучше настроить nginx, чтобы эти вызовы можно было "вовремя перехватывать" и соответствующим образом разрешать. Любые идеи приветствуются. :)
PS: Мы также попробовали Apache с похожей конфигурацией, та же проблема возникает и в Strace.
Редактировать: Мне просто нужна какая-то директива местоположения в конфигурации моего сайта, чтобы решить эту проблему? Я использую базовую конфигурацию nginx из официальной документацииhttps://laravel.com/docs/8.x/deployment#nginxс несколькими дополнениями, такими как:
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;
РЕДАКТИРОВАТЬ:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
У меня есть пробные файлы, как предложил Данила Вершинин в ответе
решение1
Похоже, у вас try_files
проблема с производительностью. Вы можете избавиться от ненужных stat
системных вызовов,устранениеtry_files
из вашей конфигурации.
Директива try_files
предоставляет удобный и простой шаблон для создания SEO-дружественного веб-сайта.
Однако недостатком этой простоты являются дополнительные затраты на ненужные stat
системные вызовы.
Поскольку вы знаете, что, например, все /api/
URL-адреса должны быть направлены через ваш PHP, нет необходимости проверять наличие каких-либо файлов, и вы можете безоговорочно направлять данные через файл начальной загрузки Laravel, например:
location /api/ {
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
fastcgi_pass unix:/var/run/php-fpm/example.com.sock;
}
Более того, в общем случае, вы хотите иметь кэшированную информацию NGINX о существовании файлов/каталогов. Это может быть достигнуто черезоткрытый_файл_кэш.