摘要:模式,單實例多進程,常用于多語言混編,比如等,不支持端口復用,需要自己做應用的端口分配和負載均衡的子進程業務代碼。就是我們需要一個調度者,保證所有后端服務器都將性能充分發揮,從而保持服務器集群的整體性能最優,這就是負載均衡。
Node.js是從純前端走向更高階層的前端,以及全棧工程師的唯一快速途徑
簡單的說Node.js 就是運行在服務端的 JavaScript
Node.js 是一個基于Chrome JavaScript 運行時建立的一個平臺
Node.js是一個事件驅動I/O服務端JavaScript環境,基于Google的V8引擎,V8引擎執行Javascript的速度非常快,性能非常好
如果你是一個前端程序員,你不懂得像PHP、Python或Ruby等動態編程語言,然后你想創建自己的服務,那么Node.js是一個非常好的選擇Node.js 是運行在服務端的 JavaScript,如果你熟悉Javascript,那么你將會很容易的學會Node.js
當然,如果你是后端程序員,想部署一些高性能的服務,那么學習Node.js也是一個非常好的選擇
Node.JS適合運用在高并發、I/O密集、少量業務邏輯的場景 Node.js的模塊組成如下: Node.js的運行機制V8引擎解析JavaScript腳本
解析后的代碼,調用Node API
libuv庫負責Node API的執行。它將不同的任務分配給不同的線程,形成一個EventLoop(事件循環),以異步的方式將任務的執行結果返回給V8引擎。
V8引擎再將結果返回給用戶。
事件循環(Event Loop)Nodejs 執行之后會初始化一個事件循環,執行代碼程序(這些程序可能會造成異步調用、定時器或者process.nextTick()),然后開始執行事件循環。
事件循環的執行循序:
上邊的每一個模塊都是事件循環的一個階段,每個階段都有一個要執行的回調的FIFO隊列。雖然每個階段都不同,一般來說,當事件執行到一個階段,先執行這個階段特有的操作,然后操作這個階段的隊列,當隊列執行完或者達到了回調上限,事件循環就會執行下一個階段。
各個階段執行的任務如下:
timers 階段: 這個階段執行setTimeout和setInterval預定的callback;
I/O callbacks 階段: 執行除了close事件的callbacks、被timers設定的callbacks、setImmediate()設定的callbacks這些之外的callbacks;
idle, prepare 階段: 僅node內部使用;
poll 階段: 獲取新的I/O事件, 適當的條件下node將阻塞在這里;
check 階段: 執行setImmediate() 設定的callbacks;
close callbacks 階段: 執行socket.on("close", ...)這些 callback
process.nextTick()不屬于上面的任何一個phase,它在每個phase結束的時候都會運行。也可以認為,nextTick在下一個異步方法的事件回調函數調用前執行。
TIPS: Node.js中的事件循環機制不會掉頭,只會由上往下,循環執行。完整的一次執行機制可以這樣描述
在Node.js中,絕大部分API都是異步的,有一個很形象的故事描述了JAVA和Node.js的區別,JAVA是一個餐廳100個服務員對應100客戶,Node.js是一個服務員玩命干,也對應100個客戶,上菜的速度很大一部分取決于廚師的做菜速度Node.js的單線程并不是真正的單線程,只是開啟了單個線程進行業務處理(cpu的運算),同時開啟了其他線程專門處理I/O。當一個指令到達主線程,主線程發現有I/O之后,直接把這個事件傳給I/O線程,不會等待I/O結束后,再去處理下面的業務,而是拿到一個狀態后立即往下走,這就是“單線程”、“異步I/O”。
I/O操作完之后呢?Node.js的I/O 處理完之后會有一個回調事件,這個事件會放在一個事件處理隊列里頭,在進程啟動時node會創建一個類似于While(true)的循環,它的每一次輪詢都會去查看是否有事件需要處理,是否有事件關聯的回調函數需要處理,如果有就處理,然后加入下一個輪詢,如果沒有就退出進程,這就是所謂的“事件驅動”。這也從Node的角度解釋了什么是”事件驅動”。
在node.js中,事件主要來源于網絡請求,文件I/O等,根據事件的不同對觀察者進行了分類,有文件I/O觀察者,網絡I/O觀察者。事件驅動是一個典型的生產者/消費者模型,請求到達觀察者那里,事件循環從觀察者進行消費,主線程就可以馬不停蹄的只關注業務不用再去進行I/O等待。
優點: Node 公開宣稱的目標是 “旨在提供一種簡單的構建可伸縮網絡程序的方法”。我們來看一個簡單的例子,在 Java和 PHP 這類語言中,每個連接都會生成一個新線程,每個新線程可能需要2MB的配套內存。在一個擁有8GBRAM的系統上,理論上最大的并發連接數量是4,000個用戶。隨著您的客戶群的增長,如果希望您的Web應用程序支持更多用戶,那么,您必須添加更多服務器。所以在傳統的后臺開發中,整個Web應用程序架構(包括流量、處理器速度和內存速度)中的瓶頸是:服務器能夠處理的并發連接的最大數量。這個不同的架構承載的并發數量是不一致的。
而Node的出現就是為了解決這個問題:更改連接到服務器的方式。在Node 聲稱它不允許使用鎖,它不會直接阻塞 I/O 調用。Node在每個連接發射一個在 Node 引擎的進程中運行的事件,而不是為每個連接生成一個新的 OS 線程(并為其分配一些配套內存)。
缺點:如上所述,nodejs的機制是單線程,這個線程里面,有一個事件循環機制,處理所有的請求。在事件處理過程中,它會智能地將一些涉及到IO、網絡通信等耗時比較長的操作,交由worker-threads去執行,執行完了再回調,這就是所謂的異步IO非阻塞吧。但是,那些非IO操作,只用CPU計算的操作,它就自己扛了,比如算什么斐波那契數列之類。它是單線程,這些自己扛的任務要一個接著一個地完成,前面那個沒完成,后面的只能干等。因此,對CPU要求比較高的CPU密集型任務多的話,就有可能會造成號稱高性能,適合高并發的node.js服務器反應緩慢。
Node.js高并發使用Nginx+pm2,pm2中可以開啟多線程負載均衡,模式分兩種:pm2簡介: PM2是node進程管理工具,可以利用它來簡化很多node應用管理的繁瑣任務,如性能監控、自動重啟、負載均衡等,而且使用非常簡單。
下面就對PM2進行入門性的介紹,基本涵蓋了PM2的常用的功能和配置。
fork模式,單實例多進程,常用于多語言混編,比如php、python等,不支持端口復用,需要自己做應用的端口分配和負載均衡的子進程業務代碼。
缺點就是單服務器實例容易由于異常會導致服務器實例崩潰。
cluster模式,多實例多進程,但是只支持node,端口可以復用,不需要額外的端口配置,0代碼實現負載均衡。
優點就是由于多實例機制,可以保證服務器的容錯性,就算出現異常也不會使多個服務器實例同時崩潰。
共同點,由于都是多進程,都需要消息機制或數據持久化來實現數據共享。
pm2部署,默認開啟負載均衡:npm i pm2 -g
$ pm2 start app.js # 啟動app.js應用程序
$ pm2 start app.js -i 4 # cluster mode 模式啟動4個app.js的應用實例 # 4個應用程序會自動進行負載均衡
pm2 start app.js -i max 根據你的cpu數量最大化啟動多線程進行負載均衡
如果要停止所有應用,可以pm2 stop all
查看進程狀態 pm2 list
pm2真心很好很強大,可以在線熱更新代碼,更多的指令需要上官網看
pm2和Nginx配合pm2 + nginx
無非就是在nginx上做個反向代理配置,直接貼配置。
upstream my_nodejs_upstream { server 127.0.0.1:3001; } server { listen 80; server_name my_nodejs_server; root /home/www/project_root; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_max_temp_file_size 0; proxy_pass http://my_nodejs_upstream/; proxy_redirect off; proxy_read_timeout 240s; }
特別說明,我們不建議使用Node.js作為底層服務器,更多時候作為中間件和接入層使用,例如Electron開發跨平臺應用
Nginx開啟多線程,負載均衡
負載均衡的作用負載均衡:分攤到多個操作單元上進行執行,和它的英文名稱很匹配。就是我們需要一個調度者,保證所有后端服務器都將性能充分發揮,從而保持服務器集群的整體性能最優,這就是負載均衡。
負載均衡這里面涉及的東西相對也是比較多的,理論就不說太多了,網上,書上很多,今天我們就利用Nginx服務器來實現一個簡單的負載均衡 負載均衡算法源地址哈希法:根據獲取客戶端的IP地址,通過哈希函數計算得到一個數值,用該數值對服務器列表的大小進行取模運算,得到的結果便是客服端要訪問服務器的序號。采用源地址哈希法進行負載均衡,同一IP地址的客戶端,當后端服務器列表不變時,它每次都會映射到同一臺后端服務器進行訪問。
輪詢法:將請求按順序輪流地分配到后端服務器上,它均衡地對待后端的每一臺服務器,而不關心服務器實際的連接數和當前的系統負載。
隨機法:通過系統的隨機算法,根據后端服務器的列表大小值來隨機選取其中的一臺服務器進行訪問。
加權輪詢法:不同的后端服務器可能機器的配置和當前系統的負載并不相同,因此它們的抗壓能力也不相同。給配置高、負載低的機器配置更高的權重,讓其處理更多的請;而配置低、負載高的機器,給其分配較低的權重,降低其系統負載,加權輪詢能很好地處理這一問題,并將請求順序且按照權重分配到后端。
加權隨機法:與加權輪詢法一樣,加權隨機法也根據后端機器的配置,系統的負載分配不同的權重。不同的是,它是按照權重隨機請求后端服務器,而非順序。
最小連接數法:由于后端服務器的配置不盡相同,對于請求的處理有快有慢,最小連接數法根據后端服務器當前的連接情況,動態地選取其中當前積壓連接數最少的一臺服務器來處理當前的請求,盡可能地提高后端服務的利用效率,將負責合理地分流到每一臺服務器。
下載Nginx,找到config文件夾下面的nginx.conf,修改下面配置文件
每個
upstream test{ server 11.22.333.11:6666 weight=1; server 11.22.333.22:8888 down; server 11.22.333.33:8888 backup; server 11.22.333.44:5555 weight=2; } //down 表示單前的server臨時不參與負載. //weight 默覺得1.weight越大,負載的權重就越大 //backup: 其他全部的非backup機器down或者忙的時候,請求backup機器。所以這臺機器壓力會最輕nginx命令匯總 :
nginx 服務器重啟命令,關閉 nginx -s reload :修改配置后重新加載生效 nginx -s reopen :重新打開日志文件 nginx -t -c /path/to/nginx.conf 測試nginx配置文件是否正確 關閉nginx: nginx -s stop :快速停止nginx quit :完整有序的停止nginx 其他的停止nginx 方式: ps -ef | grep nginx kill -QUIT 主進程號 :從容停止Nginx kill -TERM 主進程號 :快速停止Nginx pkill -9 nginx :強制停止Nginx 啟動nginx: nginx -c /path/to/nginx.conf 平滑重啟nginx: kill -HUP 主進程號在開啟Nginx多線程負載均衡和部署pm2負載均衡后的架構圖:
第一種,Node.js作為底層服務器,直接操作數據庫的方式:
第二種,Node.js作為中間件,訪問底層服務器的方式:
高并發下性能對比,Apache、Nginx 與 Node.js 之爭高并發下的性能測試對比:
參考文章 : 巨頭終極對決,Apache、Nginx 與 Node.js 之爭
所有的測試都在本地運行:
英特爾酷睿 i7-2600k,四核八線程的機器
Gentoo Linux 是用于測試的操作系統
用于基準測試的工具:ApacheBench,2.3 <$Revision: 1748469 $>
測試包括一系列基準,從 1000 到 10000 個請求以及從 100 到 1000 個的并發請求——結果相當令人驚訝。
高并發測試結果對比:Apache、Nginx 與 Node 的對比:請求負載的性能(每 100 位并發用戶)
Apache、Nginx 與 Node 的對比:用戶負載能力(每 1000 個請求)
壓力測試
我們可以從結果中得到什么?
從以上結果判斷,似乎 Nginx 可以在最少的時間內完成最多請求,換句話來說,Nginx 是最快的 HTTP 服務器。
還有一個相當驚人的事實是,在特定的用戶并發數和請求數下,Node.js 可以比 Nginx 和 Apache 更快。
但當請求的數量在并發測試中增加的時候,Nginx 將重回領先的位置,這個結果可以讓那些陷入 Node.js 的遐想的人清醒一下。
和 Apache、Nginx 不同的是,Node.js 似乎對用戶的并發數不太敏感,尤其是在集群節點。如圖所示,集群節點在 0.1 秒左右保持一條直線,而 Apache 和 Nginx 都有大約 0.2 秒的波動。
基于上述統計可以得出的結論是:網站比較小,其使用的服務器就無所謂。然而,隨著網站的受眾越來越多,HTTP 服務器的影響變得愈加明顯。
當涉及到每臺服務器的原始速度的底線的時候,正如壓力測試所描述的,我的感覺是,性能背后最關鍵的因素不是一些特定的算法,而實際上是運行的每臺服務器所用的編程語言。
由于 Apache 和 Nginx 都使用了 C 語言—— AOT 語言(編譯型語言),而 Node.js 使用了 JavaScript ——這是一種 JIT 語言(解釋型語言)。這意味著 Node.js 在執行程序的過程中還有額外的工作負擔。
這意味著我不能僅僅基于上面的結果來下結論,而要做進一步校驗,正如你下面看到的結果,當我使用一臺經過優化的 Node.js 服務器與流行的 Express 框架時,我得到幾乎相同的性能結論。
全面考慮
逝者如斯夫,如果沒有服務的內容,HTTP 服務器是沒什么用的。因此,在比較 we服務器的時候,我們必須考慮的一個重要的部分就是我們希望在上面運行的內容。
雖然也有其它的功能,但是 HTTP 服務器最廣泛的使用就是運行網站。因此,為了看到每臺服務器的性能的實際效果,我決定比較一下世界上使用最廣泛的 CMS(內容管理系統)WordPress 和 Ghost —— 內核使用了 JavaScript 的一顆冉冉升起的明星。
基于 JavaScript 的 Ghost 網頁能否勝過運行在 PHP 和 Apache / Nginx 上面的 WordPress 頁面?
這是一個有趣的問題,因為 Ghost 具有操作工具單一且一致的優點——無需額外的封裝,而 WordPress 需要依賴 Apache / Nginx 和 PHP 之間的集成,這可能會導致顯著的性能缺陷。
除此之外,PHP 距 Node.js 之間還有一個顯著的性能落差,后者更佳,我將在下面簡要介紹一下,可能會出現一些與初衷大相徑庭的結果。
PHP 與 Node.js 的對決
為了比較 WordPress 和 Ghost,我們必須首先考慮一個影響到兩者的基本組件。
基本上,WordPress 是一個基于 PHP 的 CMS,而 Ghost 是基于 Node.js(JavaScript)的。與 PHP 不同,Node.js 有以下優點:
非阻塞的 I/O
事件驅動
更新穎、更少的殘舊代碼
由于有大量的測評文章解釋和演示了 Node.js 的原始速度超過 PHP(包括 PHP 7),我不會再進一步闡述這個主題,請你自行用谷歌搜索相關內容。
因此,考慮到 Node.js 的性能優于 PHP,一個 Node.js 的網站的速度要比 Apache / Nginx 和 PHP 的網站快嗎?
WordPress 和 Ghost 對決
當比較 WordPress 和 Ghost 時,有些人會說這就像比較蘋果和橘子,大多數情況下我同意這個觀點,因為 WordPress 是一個完全成熟的 CMS,而 Ghost 基本上只是一個博客平臺。
然而,兩者仍然有共同競爭的市場,這兩者都可以用于向世界發布你的個人文章。
制定一個前提,我們怎么比較兩個完全基于不同的代碼來運行的平臺,包括風格主題和核心功能。
事實上,一個科學的實驗測試條件是很難設計的。然而,在這個測試中我對更接近生活的情景更感興趣,所以 WordPress 和 Ghost 都將保留其主題。因此,這里的目標是使兩個平臺的網頁大小盡可能相似,讓 PHP 和 Node.js 在幕后斗智斗勇。
由于結果是根據不同的標準進行測量的,最重要的是尺度不一樣,因此在圖表中并排顯示它們是不公平的。因此,我改為使用表:
Node、Nginx、Apache 以及運行 WordPress 和 Ghost 的比較。前兩行是 WordPress,底部的兩行是 Ghost
Node、Nginx、Apache 以及運行 WordPress 和 Ghost 的比較。前兩行是 WordPress,底部的兩行是 Ghost
正如你所見,盡管事實上 Ghost(Node.js)正在加載一個更小的頁面(你可能會驚訝 1kb 可以產生這么大的差異),它仍然比同時使用 Nginx 和 Apache 的 WordPress 要慢。
此外,使用 Nginx 代理作為負載均衡器來接管每個 Node 服務器的請求實際上會提升還是降低性能?
那么,根據上面的表格,如果說它產生什么效果的話,它造成了更慢的效果——這是一個合理的結果,因為額外封裝一層理所當然會使其變得更慢。當然,上面的數字也表明這點差異可以忽略不計。
但是上表中最重要的一點是,即使 Node.js 比 PHP 快,HTTP 服務器的作用也可能超過某個 web 平臺使用的編程語言的重要性。
當然,另一方面,如果加載的頁面更多地依賴于服務器端的腳本處理,那么我懷疑結果可能會有點不同。
最后,如果一個 web 平臺真的想在這場競賽里擊敗 WordPress,從這個比較中得出的結論就是,要想性能占優,必須要定制一些像 PHP-FPM 的工具,它將直接與 JavaScript 通信(而不是作為服務器來運行),因此它可以完全發揮 JavaScript 的力量來達到更好的性能。
Node.js的生態圈匯總:Node.js遵循commonJS規范,要說它的生態圈,第一個肯定是webpack,用不好Node.js的人肯定用不好webpack,所以說Node.js的一個突破初級前端工程師的好學習方向
express koa koa2 egg一系列的Node.js框架,在Restful架構下使用,完成常規的一些http,ajax請求響應
GraphQL,GraphQL 是一種 API 所使用的查詢語言,不止Node.js有,其他語言也有,不止可以查詢,還可以多數據庫CRUD操作,解決了一部分RestFul架構帶來的問題
mongodb,非關系型數據庫,輕量級別數據庫,目前Node.js配合使用的比較多的數據庫,在Node.js中我們一般使用 mongoose這個庫來配合使用
sqlite,SQLite是一個進程內的庫,實現了自給自足的、無服務器的、零配置的、事務性的 SQL 數據庫引擎。它是一個零配置的數據庫,這意味著與其他數據庫一樣,您不需要在系統中配置。就像其他數據庫,SQLite 引擎不是一個獨立的進程,可以按應用程序需求進行靜態或動態連接。SQLite 直接訪問其存儲文件。
Electron,跨平臺桌面開發,可以使用Node.js的API,V8的環境也被打包在內。
C++插件,Node.js的V8環境就是C++寫的,自然也是可以使用C++插件
Redis,數據緩存層,Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹復制。存盤可以有意無意的對數據進行寫操作。由于完全實現了發布/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道并接收主服務器完整的消息發布記錄。同步對讀取操作的可擴展性和數據冗余很有幫助。
SSR, 以React為例,在中間層對代碼進行注水,在客戶端對代碼脫水,實現部分首屏SSR,優化首屏渲染時間。
websocket通訊等
puppeteer爬蟲
總結一下Node.jsNode.js在目前前端的開發中,是一項不可或缺的技能,它也是讓我們走向真正全棧工程師的路不那么陡峭
Node.js適用場景,非密集型計算型
Node.js最核心的部分不止是RestFul架構的那一套接受請求,返回數據。還有文件IO,流,Buffer,redis層這一類的操作
Node.js配合Nginx進行負載均衡,不僅能提升性能,更能替后端真正減輕很多負擔,完成許多特定的需求。
Node.js在做接入層,比如Electron中,可以調用很多Node API,完成渲染進程不能做的事情,例如文件io,buffer操作等
今天由于時間有限,很多東西都沒有細化下去寫,可能還是有不少漏掉的,以后都會慢慢補上,走過路過,點點贊,咱們永遠都是A
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/114792.html
摘要:模式,單實例多進程,常用于多語言混編,比如等,不支持端口復用,需要自己做應用的端口分配和負載均衡的子進程業務代碼。就是我們需要一個調度者,保證所有后端服務器都將性能充分發揮,從而保持服務器集群的整體性能最優,這就是負載均衡。 showImg(https://segmentfault.com/img/remote/1460000019425391?w=1440&h=1080); Nod...
摘要:模式,單實例多進程,常用于多語言混編,比如等,不支持端口復用,需要自己做應用的端口分配和負載均衡的子進程業務代碼。就是我們需要一個調度者,保證所有后端服務器都將性能充分發揮,從而保持服務器集群的整體性能最優,這就是負載均衡。 showImg(https://segmentfault.com/img/remote/1460000019425391?w=1440&h=1080); Nod...
摘要:調用通過注冊表調用到實例,透過的,調用到中的,最后通過,調用,根據參數相應模塊執行。京東的,多端解決方案是一套遵循語法規范的多端開發解決方案。 showImg(https://segmentfault.com/img/bVbuMkw?w=1304&h=808); 對于一項技術,我們不能停留在五分鐘狀態,特別喜歡一句話,用什么方式繪制UI界面一點不重要,重要的是底層的思維,解決問題和優化...
摘要:調用通過注冊表調用到實例,透過的,調用到中的,最后通過,調用,根據參數相應模塊執行。京東的,多端解決方案是一套遵循語法規范的多端開發解決方案。 showImg(https://segmentfault.com/img/bVbuMkw?w=1304&h=808); 對于一項技術,我們不能停留在五分鐘狀態,特別喜歡一句話,用什么方式繪制UI界面一點不重要,重要的是底層的思維,解決問題和優化...
閱讀 2221·2021-11-18 10:02
閱讀 3480·2021-11-15 11:36
閱讀 1115·2019-08-30 14:03
閱讀 724·2019-08-30 11:08
閱讀 2760·2019-08-29 13:20
閱讀 3287·2019-08-29 12:34
閱讀 1374·2019-08-28 18:30
閱讀 1641·2019-08-26 13:34