溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何為高負載網(wǎng)絡(luò)優(yōu)化Nginx和Node.js

發(fā)布時間:2022-03-31 16:47:37 來源:億速云 閱讀:139 作者:iii 欄目:編程語言

這篇文章主要介紹了如何為高負載網(wǎng)絡(luò)優(yōu)化Nginx和Node.js的相關(guān)知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇如何為高負載網(wǎng)絡(luò)優(yōu)化Nginx和Node.js文章都會有所收獲,下面我們一起來看看吧。

網(wǎng)絡(luò)調(diào)優(yōu)
如果不先對nginx和node.js的底層傳輸機制有所了解,并進行針對性優(yōu)化,可能對兩者再細致的調(diào)優(yōu)也會徒勞無功。一般情況下,nginx通過tcp socket來連接客戶端與上游應(yīng)用。
我們的系統(tǒng)對tcp有許多門限值與限制,通過內(nèi)核參數(shù)來設(shè)定。這些參數(shù)的默認值往往是為一般的用途而定的,并不能滿足web服務(wù)器所需的高流量、短生命的要求。
這里列出了調(diào)優(yōu)tcp可供候選的一些參數(shù)。為使它們生效,可以將它們放在/etc/sysctl.conf文件里,或者放入一個新配置文件,比如 /etc/sysctl.d/99-tuning.conf,然后運行sysctl -p,讓內(nèi)核裝載它們。我們是用sysctl-cookbook來干這個體力活。
需要注意的是,這里列出來的值是可以安全使用的,但還是建議大家研究一下每個參數(shù)的含義,以便根據(jù)自己的負荷、硬件和使用情況選擇一個更加合適的值。

復(fù)制代碼 代碼如下:

<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
為了替上游的應(yīng)用服務(wù)下游的客戶端,nginx必須打開兩條tcp連接,一條連接客戶端,一條連接應(yīng)用。在服務(wù)器收到很多連接時,系統(tǒng)的可用端口將很快被耗盡。通過修改net.ipv4.ip_local_port_range參數(shù),可以將可用端口的范圍改大。如果在/var/log/syslog 中發(fā)現(xiàn)有這樣的錯誤: “possible syn flooding on port 80. sending cookies”,即表明系統(tǒng)找不到可用端口。增大net.ipv4.ip_local_port_range參數(shù)可以減少這個錯誤。
net.ipv4.tcp_tw_reuse
當服務(wù)器需要在大量tcp連接之間切換時,會產(chǎn)生大量處于time_wait狀態(tài)的連接。time_wait意味著連接本身是關(guān)閉的,但資源還沒有釋放。將net_ipv4_tcp_tw_reuse設(shè)置為1是讓內(nèi)核在安全時盡量回收連接,這比重新建立新連接要便宜得多。
net.ipv4.tcp_fin_timeout
這是處于time_wait狀態(tài)的連接在回收前必須等待的最小時間。改小它可以加快回收。
如何檢查連接狀態(tài)
使用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服務(wù)器的負載逐漸升高,我們就會開始遭遇nginx的某些奇怪限制。連接被丟棄,內(nèi)核不停報syn flood。而這時,平均負荷和cpu使用率都很小,服務(wù)器明明是可以處理更多連接的狀態(tài),真令人沮喪。
經(jīng)過調(diào)查,發(fā)現(xiàn)有非常多處于time_wait狀態(tài)的連接。這是其中一個服務(wù)器的輸出:
有47135個time_wait連接!而且,從ss可以看出,它們都是已經(jīng)關(guān)閉的連接。這說明,服務(wù)器已經(jīng)消耗了絕大部分可用端口,同時也暗示我們,服務(wù)器是為每個連接都分配了新端口。調(diào)優(yōu)網(wǎng)絡(luò)對這個問題有一點幫助,但是端口仍然不夠用。
經(jīng)過繼續(xù)研究,我找到了一個關(guān)于上行連接keepalive指令的文檔,它寫道:
設(shè)置通往上游服務(wù)器的最大空閑?;钸B接數(shù),這些連接會被保留在工作進程的緩存中。
有趣。理論上,這個設(shè)置是通過在緩存的連接上傳遞請求來盡可能減少連接的浪費。文檔中還提到,我們應(yīng)該把proxy_http_version設(shè)為"1.1",并清除"connection"頭部。經(jīng)過進一步的研究,我發(fā)現(xiàn)這是一種很好的想法,因為http/1.1相比http1.0,大大優(yōu)化了 tcp連接的使用率,而nginx默認用的是http/1.0。
按文檔的建議修改后,我們的上行配置文件變成這樣:

復(fù)制代碼 代碼如下:

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一節(jié)的proxy設(shè)置。同時,加了一個 p roxy_next_upstream來跳過故障的服務(wù)器,調(diào)整了客戶端的 keepalive_timeout,并關(guān)閉訪問日志。配置變成這樣:

復(fù)制代碼 代碼如下:

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;
}

采用新的配置后,我發(fā)現(xiàn)服務(wù)器們占用的socket 降低了90%?,F(xiàn)在可以用少得多的連接來傳輸請求了。新的輸出如下:
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
node.js
得益于事件驅(qū)動式設(shè)計可以異步處理i/o,node.js開箱即可處理大量的連接和請求。雖然有其它一些調(diào)優(yōu)手段,但這篇文章將主要關(guān)注node.js的進程方面。
node是單線程的,不會自動使用多核。也就是說,應(yīng)用不能自動獲得服務(wù)器的全部能力。
實現(xiàn)node進程的集群化
我們可以修改應(yīng)用,讓它fork多個線程,在同一個端口上接收數(shù)據(jù),從而實現(xiàn)負載的跨越多核。node有一個cluster模塊,提供了實現(xiàn)這個目標所必需的所有工具,但要將它們加入應(yīng)用中還需要很多體力活。如果你用的是express,ebay有一個叫cluster2的模塊可以用。
防止上下文切換
當運行多個進程時,應(yīng)該確保每個cpu核同一時間只忙于一個進程。一般來說,如果cpu有n個核,我們應(yīng)該生成n-1個應(yīng)用進程。這樣可以確保每個進程都能得到合理的時間片,而剩下的一個核留給內(nèi)核調(diào)度程序運行其它任務(wù)。我們還要確保服務(wù)器上基本不執(zhí)行除node.js外的其它任務(wù),防止出現(xiàn)cpu 的爭用。
我們曾經(jīng)犯過一個錯誤,在服務(wù)器上部署了兩個node.js應(yīng)用,然后每個應(yīng)用都開了n-1個進程。結(jié)果,它們互相之間搶奪cpu,導(dǎo)致系統(tǒng)的負荷急升。雖然我們的服務(wù)器都是8核的機器,但仍然可以明顯地感覺到由上下文切換引起的性能開銷。上下文切換是指cpu為了執(zhí)行其它任務(wù)而掛起當前任務(wù)的現(xiàn)象。在切換時,內(nèi)核必須掛起當前進程的所有狀態(tài),然后裝載和執(zhí)行另一個進程。為了解決這個問題,我們減少了每個應(yīng)用開啟的進程數(shù),讓它們公平地分享 cpu,結(jié)果系統(tǒng)負荷就降了下來:

如何為高負載網(wǎng)絡(luò)優(yōu)化Nginx和Node.js
請注意上圖,看系統(tǒng)負荷(藍線)是如何降到cpu核數(shù)(紅線)以下的。在其它服務(wù)器上,我們也看到了同樣的情況。既然總的工作量保持不變,那么上圖中的性能改善只能歸功于上下文切換的減少。

排列不分先后:

1. 當性能遇到問題時,如果能在應(yīng)用層進行計算和處理,那就把它從數(shù)據(jù)庫層拿出來。排序和分組就是典型的例子。在應(yīng)用層做性能提升總是要比在數(shù)據(jù)庫層容易的多。就像對于MySQL,sqlite更容易掌控。

2. 關(guān)于并行計算,如果能避免就盡量避免。如果無法避免,記住,能力越大,責任越大。如果有可能,盡量避免直接對線程操作。盡可能在更高的抽象層上操作。例如,在iOS中,GCD,分發(fā)和隊列操作是你的好朋友。人類的大腦沒有被設(shè)計成用來分析那些無窮臨時狀態(tài)&mdash;&mdash;這是我的慘痛教訓(xùn)所得。

3. 盡可能簡化狀態(tài),盡可能局部本地化。適用至上。

4. 短小可組合的方法是你的好朋友。

5. 代碼注釋是危險的,因為它們很容易更新不及時或給人誤導(dǎo),但這不能成為不寫注釋的理由。不要注釋雞毛蒜皮的事情,但如果需要,在某些特殊地方,戰(zhàn)略性的長篇注釋是需要的。你的記憶會背叛你,也許會在明天早上,也許會在一杯咖啡后。

6. 如果你認為一個用例場景也許“不會有問題吧”,它也許就是一個月后讓你在發(fā)布的產(chǎn)品中遭受慘痛失敗的地方。做一個懷疑主義者,測試,驗證。

7. 有疑問時,和團隊中所有相關(guān)人交流。

8. 做正確的事情&mdash;&mdash;你通常會知道這指的是什么。

9. 你的用戶并不傻,他們只是沒有耐心理解你的捷徑。

10. 如果一個開發(fā)人員沒有被安排長期的維護你們開發(fā)的系統(tǒng),對他保持警惕。80%的血、汗、淚水都是在軟件發(fā)布后的時間里流的&mdash;&mdash;那時你會變成一個厭世者,但也是更聰明的“行家”。

11. 任務(wù)清單是你的好朋友。

12. 主動讓你的工作更有樂趣,有時這需要你付出努力。

13. 悄無聲息的崩潰,我仍然會為此從噩夢中驚醒。監(jiān)控,日志,警報。清楚各種的假警報和不可避免的感覺鈍化。保持你的系統(tǒng)對故障的敏感和及時警報。

關(guān)于“如何為高負載網(wǎng)絡(luò)優(yōu)化Nginx和Node.js”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“如何為高負載網(wǎng)絡(luò)優(yōu)化Nginx和Node.js”知識都有一定的了解,大家如果還想學習更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI