您好,登錄后才能下訂單哦!
本篇內容介紹了“如何優化Nginx和Node.js”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
網絡調優
如果不先對nginx和node.js的底層傳輸機制有所了解,并進行針對性優化,可能對兩者再細致的調優也會徒勞無功。一般情況下,nginx通過tcp socket來連接客戶端與上游應用。
我們的系統對tcp有許多門限值與限制,通過內核參數來設定。這些參數的默認值往往是為一般的用途而定的,并不能滿足web服務器所需的高流量、短生命的要求。
這里列出了調優tcp可供候選的一些參數。為使它們生效,可以將它們放在/etc/sysctl.conf文件里,或者放入一個新配置文件,比如 /etc/sysctl.d/99-tuning.conf,然后運行sysctl -p,讓內核裝載它們。我們是用sysctl-cookbook來干這個體力活。
需要注意的是,這里列出來的值是可以安全使用的,但還是建議大家研究一下每個參數的含義,以便根據自己的負荷、硬件和使用情況選擇一個更加合適的值。
<span style="font-size: 14px; color: #009900; font-family: microsoft yahei"> net.ipv4.ip_local_port_range='1024 65000' net.ipv4.tcp_tw_reuse='1' net.ipv4.tcp_fin_timeout='15' net.core.netdev_max_backlog='4096' net.core.rmem_max='16777216' net.core.somaxconn='4096' net.core.wmem_max='16777216' net.ipv4.tcp_max_syn_backlog='20480' net.ipv4.tcp_max_tw_buckets='400000' net.ipv4.tcp_no_metrics_save='1' net.ipv4.tcp_rmem='4096 87380 16777216' net.ipv4.tcp_syn_retries='2' net.ipv4.tcp_synack_retries='2' net.ipv4.tcp_wmem='4096 65536 16777216' vm.min_free_kbytes='65536' </span>
重點說明其中幾個重要的。
net.ipv4.ip_local_port_range
為了替上游的應用服務下游的客戶端,nginx必須打開兩條tcp連接,一條連接客戶端,一條連接應用。在服務器收到很多連接時,系統的可用端口將很快被耗盡。通過修改net.ipv4.ip_local_port_range參數,可以將可用端口的范圍改大。如果在/var/log/syslog 中發現有這樣的錯誤: “possible syn flooding on port 80. sending cookies”,即表明系統找不到可用端口。增大net.ipv4.ip_local_port_range參數可以減少這個錯誤。
net.ipv4.tcp_tw_reuse
當服務器需要在大量tcp連接之間切換時,會產生大量處于time_wait狀態的連接。time_wait意味著連接本身是關閉的,但資源還沒有釋放。將net_ipv4_tcp_tw_reuse設置為1是讓內核在安全時盡量回收連接,這比重新建立新連接要便宜得多。
net.ipv4.tcp_fin_timeout
這是處于time_wait狀態的連接在回收前必須等待的最小時間。改小它可以加快回收。
如何檢查連接狀態
使用netstat: netstat -tan | awk '{print $6}' | sort | uniq -c
或使用ss:
ss -s nginx ss -s total: 388 (kernel 541) tcp: 47461 (estab 311, closed 47135, orphaned 4, synrecv 0, timewait 47135/0), ports 33938 transport total ip ipv6 * 541 - - raw 0 0 0 udp 13 10 3 tcp 326 325 1 inet 339 335 4 frag 0 0 0
隨著web服務器的負載逐漸升高,我們就會開始遭遇nginx的某些奇怪限制。連接被丟棄,內核不停報syn flood。而這時,平均負荷和cpu使用率都很小,服務器明明是可以處理更多連接的狀態,真令人沮喪。
經過調查,發現有非常多處于time_wait狀態的連接。這是其中一個服務器的輸出:
有47135個time_wait連接!而且,從ss可以看出,它們都是已經關閉的連接。這說明,服務器已經消耗了絕大部分可用端口,同時也暗示我們,服務器是為每個連接都分配了新端口。調優網絡對這個問題有一點幫助,但是端口仍然不夠用。
理論上,這個設置是通過在緩存的連接上傳遞請求來盡可能減少連接的浪費。文檔中還提到,我們應該把proxy_http_version設為"1.1",并清除"connection"頭部。經過進一步的研究,我發現這是一種很好的想法,因為http/1.1相比http1.0,大大優化了 tcp連接的使用率,而nginx默認用的是http/1.0。
按文檔的建議修改后,我們的上行配置文件變成這樣:
upstream backend_nodejs { server nodejs-3:5016 max_fails=0 fail_timeout=10s; server nodejs-4:5016 max_fails=0 fail_timeout=10s; server nodejs-5:5016 max_fails=0 fail_timeout=10s; server nodejs-6:5016 max_fails=0 fail_timeout=10s; keepalive 512; }
我還按它的建議修改了server一節的proxy設置。同時,加了一個 p roxy_next_upstream來跳過故障的服務器,調整了客戶端的 keepalive_timeout,并關閉訪問日志。配置變成這樣:
server { listen 80; server_name fast.gosquared.com; client_max_body_size 16m; keepalive_timeout 10; location / { proxy_next_upstream error timeout http_500 http_502 http_503 http_504; proxy_set_header connection ""; proxy_http_version 1.1; proxy_pass http://backend_nodejs; } access_log off; error_log /dev/null crit; }
采用新的配置后,我發現服務器們占用的socket 降低了90%。現在可以用少得多的連接來傳輸請求了。新的輸出如下:
ss -s total: 558 (kernel 604) tcp: 4675 (estab 485, closed 4183, orphaned 0, synrecv 0, timewait 4183/0), ports 2768 transport total ip ipv6 * 604 - - raw 0 0 0 udp 13 10 3 tcp 492 491 1 inet 505 501 4
得益于事件驅動式設計可以異步處理i/o,node.js開箱即可處理大量的連接和請求。雖然有其它一些調優手段,但這篇文章將主要關注node.js的進程方面。
node是單線程的,不會自動使用多核。也就是說,應用不能自動獲得服務器的全部能力。
實現node進程的集群化
我們可以修改應用,讓它fork多個線程,在同一個端口上接收數據,從而實現負載的跨越多核。node有一個cluster模塊,提供了實現這個目標所必需的所有工具,但要將它們加入應用中還需要很多體力活。如果你用的是express,ebay有一個叫cluster2的模塊可以用。
防止上下文切換
當運行多個進程時,應該確保每個cpu核同一時間只忙于一個進程。一般來說,如果cpu有n個核,我們應該生成n-1個應用進程。這樣可以確保每個進程都能得到合理的時間片,而剩下的一個核留給內核調度程序運行其它任務。我們還要確保服務器上基本不執行除node.js外的其它任務,防止出現cpu 的爭用。
我們曾經犯過一個錯誤,在服務器上部署了兩個node.js應用,然后每個應用都開了n-1個進程。結果,它們互相之間搶奪cpu,導致系統的負荷急升。雖然我們的服務器都是8核的機器,但仍然可以明顯地感覺到由上下文切換引起的性能開銷。上下文切換是指cpu為了執行其它任務而掛起當前任務的現象。在切換時,內核必須掛起當前進程的所有狀態,然后裝載和執行另一個進程。為了解決這個問題,我們減少了每個應用開啟的進程數,讓它們公平地分享 cpu,結果系統負荷就降了下來:
請注意上圖,看系統負荷(藍線)是如何降到cpu核數(紅線)以下的。在其它服務器上,我們也看到了同樣的情況。既然總的工作量保持不變,那么上圖中的性能改善只能歸功于上下文切換的減少。
“如何優化Nginx和Node.js”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。