我有一個在生產環境中運行的 Laravel 應用程序,並且有一些經常使用的 API。有些東西造成了瓶頸,導致我們的伺服器停頓(3 個帶有負載平衡器)。在優化了 Laravel 的基礎知識、快取配置、路由、資料等之後,甚至解決了所有 n+1 個問題,我們在高峰時段仍然遇到問題。有人建議我們在其中一個 nginx 工作線程上運行 strace 來查看系統級別發生了什麼,所以我們這麼做了,而且很有趣的是,有很多冗餘的系統調用,在調用 API 時 nginx 會嘗試查找文件:
部分蹤跡:
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
現在,在本例中,使用 ID 呼叫 API 3d4f7518e04e9
,並嘗試循環遍歷目錄來尋找該檔案。但它不是一個文件,而是一個 API。我們運行 strace 的時間不到 30 秒,並且有 5k 個這樣的調用,這對我來說沒有意義。
那麼,這些電話有必要嗎?我不這麼認為,但請告訴我我是否錯了。如果我是對的,我怎麼能更好地配置我的 nginx,以便這些呼叫可以「及時捕獲」並得到適當的解決。歡迎任何想法。 :)
PS:我們也嘗試過類似配置的apache,strace中出現了同樣的問題。
編輯:我是否只需要在網站配置中添加某種位置指令來解決此問題?我正在使用官方文件中的基本 nginx confhttps://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;
}
我確實嘗試了 Danila Vershinin 在答案中建議的文件
答案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 快取有關檔案/目錄存在的資訊。這可以透過以下方式實現開啟檔案快取。