Centos

查找導致隨機 502 網關錯誤的 Nginx/PHP-FPM 瓶頸

  • January 7, 2012

我為一個相當繁忙的網際網路站點工作,該站點經常會出現非常大的流量高峰。在這些峰值期間,每秒請求數百頁,這會產生隨機的 502 網關錯誤。

現在我們在一台機器上執行 Nginx (1.0.10) 和 PHP-FPM,該機器具有 4 個 SAS 15k 驅動器 (raid10),具有 16 核 CPU 和 24GB DDR3 記憶體。我們還使用最新的 Xcache 版本。數據庫位於另一台機器上,但是這台機器的負載非常低,沒有問題。

在正常負載下,一切執行完美,系統負載低於 1,PHP-FPM 狀態報告從未真正同時顯示超過 10 個活動程序。始終有大約 10GB 的記憶體可用。在正常負載下,機器每秒處理大約 100 次瀏覽量。

當巨大的流量峰值到達時,問題就出現了,並且每秒從機器請求*數百次頁面瀏覽量。*我注意到 FPM 的狀態報告隨後會顯示多達 50 個活動程序,但這仍然遠低於我們配置的 300 個最大連接數。在這些峰值期間,Nginx 狀態報告多達 5000 個活動連接,而不是正常的平均 1000 個。

作業系統資訊:CentOS 5.7 版(最終版)

CPU: Intel(R) Xeon(R) CPU E5620 @ 2.40GH (16 cores)

php-fpm.conf

daemonize = yes
listen = /tmp/fpm.sock
pm = static
pm.max_children = 300
pm.max_requests = 1000

我沒有設置 rlimit_files,因為據我所知,如果你不這樣做,它應該使用系統預設值。

fastcgi_params(僅向標准文件添加值)

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

fastcgi_pass            unix:/tmp/fpm.sock;

nginx.conf

worker_processes        8;
worker_connections      16384;
sendfile                on;
tcp_nopush              on;
keepalive_timeout       4;

Nginx 通過 Unix Socket 連接到 FPM。

sysctl.conf

net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 1
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.eth0.rp_filter=1
net.ipv4.conf.lo.rp_filter=1
net.ipv4.ip_conntrack_max = 100000

限制.conf

* soft nofile 65536
* hard nofile 65536

以下是以下命令的結果:

ulimit -n
65536

ulimit -Sn
65536

ulimit -Hn
65536

cat /proc/sys/fs/file-max
2390143

**問題:**如果 PHP-FPM 沒有耗盡連接,負載仍然很低,並且有足夠的 RAM 可用,那麼在高流量期間,什麼瓶頸可能導致這些隨機 502 網關錯誤?

注意:預設情況下,這台機器的 ulimit 是 1024,因為我將它更改為 65536,所以我沒有完全重新啟動機器,因為它是生產機器,這意味著太多的停機時間。

官方推薦:worker_processes = CPU核數

worker_processes 16;

來自負載均衡器(例如 HAProxy 和 nginx)的零星 502 錯誤通常是由於 LB 和 Web 伺服器之間的中間流中斷造成的。

嘗試通過 GDB 執行您的一個 Web 伺服器或它的測試副本,並查看在生成測試流量時是否看到分段錯誤(使用 ab 或 jMeter 或類似來模擬流量)。

我最近不得不解決一個非常相似的場景/問題。我已經排除了導致問題的資源等,因為我有非常全面的監控可以幫助我。最後,我發現 502 錯誤來自負載均衡器後面的 Web 伺服器向 LB 返回無效(在本例中為空)HTTP 響應。

我使用了其中一台 Web 伺服器並停止了 Web 伺服器,然後通過 gdb 再次啟動它,然後瀏覽了站點。最終,在一些點擊之後,我看到發生了分段錯誤,這導致 502 錯誤可見。我從 GDB 獲取回溯並將其作為錯誤送出給 PHP 團隊,但對我來說唯一的修復是切換分發以解決存在的 PHP 錯誤。

段錯誤導致 Web 伺服器向 LB 發送無效內容,並且 LB 顯示 502 錯誤,因為就它而言,Web 伺服器已“中途”消失。

我知道這並不能直接回答您的問題,但這是一個開始尋找的地方。假設您確實看到了段錯誤,您可以從 GDB 獲取堆棧跟踪,然後您可以希望向後工作並找到導致段錯誤的函式。

引用自:https://serverfault.com/questions/347688