1. 程式人生 > >uwsgi-listen-queue-full解決方案

uwsgi-listen-queue-full解決方案

web伺服器使用的是nginx + uwsgi 的架構;近期發現伺服器上偶然會出現特殊日誌;並且很難重現,有時候出現一段時間會自己迴歸正常。


問題背景:

web伺服器使用的是nginx + uwsgi 的架構;

近期發現伺服器上偶然會出現

1***uWSGI listen queue of socket4full!!!(100/100)***

這樣的日誌;並且很難重現,有時候出現一段時間會自己迴歸正常,如下圖:

圖1 uwsgi listen queue full

問題分析:

由於是線上不定時重現,並且自動會好,並且表面上看應該是listen 佇列滿的原因。排除是程式碼邏輯等問題,懷疑是 資源和訪問方式問題導致的;

首先要在環境中復現這種情況,以便發現更深入的原因;

看到listen 佇列自然會找到對應的系統呼叫 int listen(int fd, int backlog);

socket listen 的時候可以指定 backlog 詳細請看下邊的定義:

An incomplete connection queue, which contains an entry for each SYN that has arrived from a client for which the server is awaiting completion of the TCP three-way handshake. These sockets are in the SYN_RCVD state .A completed connection queue, which contains an entry for each client with whom the TCP three-way handshake has completed. These sockets are in the ESTABLISHED state.The backlog argument to the listen function has historically specified the maximum value for the sum of both queues.

簡單的說backlog 就是 已完成佇列和等待完成佇列和,所以如果程式壓力大,不能及時的accept socket ,那麼佇列就可能會滿,滿了以後新來的connection 就建立不起來,這裡用c 簡單做了個驗證,伺服器端listen 後不進行accept ,backlog 設定為1 ,讓客戶端請求時,程式碼如下:

圖2 伺服器只監聽8000 但是不進行accept動作

圖3 併發訪問8000埠 TCP狀態的變化統計

我們觀察到新來的connection 建立不起來,丟棄了很多SYN包;

復現過程:

(1)根據上邊的分析,問題應該是請求壓力大造成的,所以使用了ab工具來併發構造請求;先隨便構造伺服器上的一個請求介面來測試;

1 2 ab-n1000-c300http://xxxxxx/xxxxxx/xxxxx/api_test1/

表示請求1000次,併發量是300,檢視伺服器uwsgi 的log 並無發現異常,加大併發量到500後還是正常;

(2)看來正常情況下雖然是併發很大,也不會出現這種情況,那麼就在某一個api裡邊人工讓它處理慢一點,也就是讓accept 的速度降下來:

1 2 3 4 import time print"-------------",time.time() time.sleep(10)

(3)再次使用ab 來測試。果然出現了 listen queue of socket 4 full ;

此時在看TCP的狀態的統計情況,發現果然有大量的SYN被丟棄掉 ,問題基本上就定位了;

仔細來看,該問題主要原因是由於部分api 處理慢,影響了整體元件其他api的可用性。在併發較高的情況下就會出現該問題;直接後果就是其他api不能正常提供服務;

 解決辦法:

這裡根本原因還需要分析那個慢的api 是否正常,是否可以優化,如果確實是邏輯複雜,很難優化,加上業務上確實處理不過來,那麼可以使用下邊的方案來解決該問題;

(1)增加uwsgi listen 佇列長度 :通過引數 –listen 1024 來提高監聽長度;

(2)使用UNIX Domain Socket 來替代網路Socket ,它不需要經過網路協議棧,不需要打包拆包等操作,它只是將應用程式資料從一個程序cp到另一個程序,這正好適合nginx 和 uwsgi 在同一臺機器的情況;通過 –socket /tmp/uwsgi.sock 來使用 Domain Socket;

當然兩個方法只能暫緩,不能根除;

(3)增加負載均衡,把壓力均分到其他機器上;


轉載自http://blog.nsfocus.net/uwsgi-listen-queue-full/