Nginx作為一個非常流行和成熟的Web Server和Reserve Proxy Server,網上有大量的性能優化教程,但是不同的業務場景千差萬別,什麼配置是最適合自己的,需要大量的測試和實踐以及不斷的優化改進。最近用戶呼叫量突破百萬大關之後,就遇到了一些問題,雖然不算太複雜,但也折騰了挺長時間才搞定,累積了不少經驗。
碰到的這個問題其實已經有一段時間了,有客戶給我們反饋調用超時,但是我們自己從系統監控上看都是正常的,只有幾十毫秒肯定不會超時,懷疑是不是網絡的原因,但是出現幾次後,就隱隱感覺這個問題可能不是偶發性的,應該還有深層的原因。
因為我們服務面向企業客戶的,雖然每家客戶的呼叫量可能會非常大,但每家企業客戶就那麼幾個公網IP,即使以後有上千家客戶,Nginx也可以輕鬆支撐這些並發連接。因此,首先從網路上對Nginx長連接作了優化,將長連接從原來配置的5秒鐘
改成5分鐘
,將每次建立連接請求的數目從預設的100調整到1000。
<code>keepalive_timeout 300; keepalive_requests 1000;</code>
調整完畢後,透過netstat
-anp
指令可以看到,新連線請求會減少,說明長連線已發揮作用。但過了一段時間,仍然發現有客戶呼叫超時的情況發生,從Nginx日誌中可以看到請求時間還是有超過1s的,甚至有長達20s左右的,如下所示:
並且從Zabbix上的監控發現一個現象,當connection writing或active數突然增高時,請求時間就相應的出現較多超時:
查看應用的日誌,發現執行時間並不長:
應用程式裡統計的時間,只是從業務開始執行到執行結果的時間,這個還沒有算Tomcat容器的執行時間,外部請求的執行路徑如下:
<code>client --> Nginx --> Tomcat --> App</code>
會不會是Tomcat容器本身執行有問題呢,把Tomcat請求的日誌呼叫出來,發現這個時間點前後的執行也是正常的:
從請求路徑上分析,肯定是Nginx到Tomcat這層存在一些問題。在排查這個問題的時候,突然發現有大量30s左右的超時,從Zabbix上也觀察到connection
writing
非常高,如下所示:
同時,發現TIME_WAIT
的連接特別多,從現象及抓包分析結果來看,應該是有客戶沒有開啟長連接,而我們在服務端又設置了keepalive_timeout
為5分鐘,導致大量使用過的連接等待超時,當時有接近2000個,編輯/etc/sysctl.conf
文件,增加如下兩個參數重用連接:
<code>net.ipv4.tcp_tw_reuse = 1 #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。</code>
生效之後很快下降到200以下,從Zabbix監控也看到,connection
writing
和connection active`都有明顯下降,但並沒有完全解決問題,還得找其它方面的原因。
Nginx的reqeust_time
指的是從客戶端接收到第一個位元組算起,到呼叫後端的upstream
server完成業務邏輯處理,並將傳回結果全部寫回客戶端為止的時間,那麼呼叫upstream server的時間如果能夠列印出來的話,就更容易將問題範圍縮小,幸運的是Nginx有兩個參數可以列印後端伺服器請求的時間和IP位址,在nginx.conf檔案中修改日誌的格式如下:
<code># $upstream_response_time 后端应用服务器响应时间 # $upstream_addr 后端服务器IP和端口号 log_format main '$remote_addr - [$time_local] "$request" ' '$status $body_bytes_sent ' '"$request_time" "$upstream_response_time" "$upstream_addr" "$request_body "';</code>
再觀察日誌,非常明顯地發現,大部分特別長的呼叫都來自同一台機器:
查看這台機器發現,雖然Java進程還在,但應用實際上已經當掉了,沒有真實的請求進來,將之從負載勻衡中摘掉,問題馬上得到緩解:
這台機器其實已經掛掉了,但為何Nginx沒有辨識到呢?進一步研究發現,Nginx在呼叫upstream server時,超時時間預設是60s,我們這些應用程式對回應時間要求非常高,超過1s已沒有意義,因此在nginx.conf檔案中修改預設的逾時時間,超過1s就返回:
<code># time out settings proxy_connect_timeout 1s; proxy_send_timeout 1s; proxy_read_timeout 1s;</code>运行一段时间后,问题已基本得到解决,不过还是会发现
request_time
超过1s达到5s的,但upstream_response_time
都没有超时了,说明上面的参数已起作用。
版权声明:本文为博主原创文章,未经博主允许不得转载。
以上就介绍了Nginx 性能优化,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。