nodejs的10個性能優(yōu)化技巧
下面是我們使用Node.js時遵循的10個性能規(guī)則:
1. 避免使用同步代碼
在設(shè)計上,Node.js是單線程的。為了能讓一個單線程處理許多并發(fā)的請求,你可以永遠不要讓線程等待阻塞,同步或長時間運行的操作。Node.js的一個顯著特征是:它從上到下的設(shè)計和實現(xiàn)都是為了實現(xiàn)異步。這讓它非常適合用于事件型程序。
不幸的是,還是有可能會發(fā)生同步/阻塞的調(diào)用。例如,許多文件系統(tǒng)操作同時擁有同步和異步的版本,比如writeFile和writeFileSync。即使你用代碼來控制同步方法,但還是有可能不注意地用到阻塞調(diào)用的外部函數(shù)庫。當(dāng)你這么做時,對性能的影響是極大的。
// Good: write files asynchronously fs.writeFile('message.txt', 'Hello Node', function (err) { console.log("It's saved and the server remains responsive!"); }); // BAD: write files synchronously fs.writeFileSync('message.txt', 'Hello Node'); console.log("It's saved, but you just blocked ALL requests!");
我們的初始化log在實現(xiàn)時無意地包含了一個同步調(diào)用來將內(nèi)容寫入磁盤。如果我們不做性能測試那么就會很容易忽略這個問題。當(dāng)以developer box中一個node.js實例來作為標準測試,這個同步調(diào)用將導(dǎo)致性能從每秒上千次的請求降至只有幾十個。
2.關(guān)閉套接字池
Node.js的http客戶端會自動地使用套接字池:默認地,它會限制每臺主機只能有5個套接字。雖然套接字的重復(fù)使用可能會讓資源的增加在控制之下,但如果你需要處理許多數(shù)據(jù)來自于同一主機的并發(fā)請求時,將會導(dǎo)致一系列的瓶頸。在這種情況下,增大maxSockets 的值或關(guān)閉套接字池是個好主意:
// Disable socket pooling var http = require('http'); var options = {.....}; options.agent = false; var req = http.request(options)
3.不要讓靜態(tài)資源使用Node.js
對于css和圖片等靜態(tài)資源,用標準的WebServer而不是Node.js。例如,領(lǐng)英移動使用的是nginx。我們同時還利用內(nèi)容傳遞網(wǎng)絡(luò)(CDNs),它能將世界范圍內(nèi)的靜態(tài)資拷貝到服務(wù)器上。這有兩個好處:(1)能減少我們node.js服務(wù)器的負載量(2)CDNs可以讓靜態(tài)內(nèi)容在離用戶較近的服務(wù)器上傳遞,以此來減少等待時間。
4.在客戶端渲染
讓我們快速比較一下服務(wù)器渲染和客戶端渲染的區(qū)別。如果我們用node.js在服務(wù)器端渲染,對于每個請求我們都會回送像下面這樣的HTML頁面:
<!-- An example of a simple webpage rendered entirely server side --> <!DOCTYPE html> <html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello John! </div> </body> </html>
請注意觀察這個頁面所有的內(nèi)容,除了用戶的名字,其余都是靜態(tài)內(nèi)容:對于每個用戶和頁面重載內(nèi)容都是一樣的。因此更有效的作法是讓Node.js僅以JSON形式返回頁面需要的動態(tài)內(nèi)容。
{"name": "John"}
頁面的其余部分—所有靜態(tài)的HTML標記-能放在JavaScript模板中(比如underscore.js模板):
<!-- An example of a JavaScript template that can be rendered client side --> <!DOCTYPE html> <html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello <%= name %>! </div> </body> </html>
性能的提升來自于這些地方:如第三點所說,靜態(tài)JavaScript模板能通過webserver(比如nginx)在服務(wù)器端提供,或者用更好的CDN來實現(xiàn)。此外,JavaScript模板能緩存在瀏覽器中或存儲在本地,所有初始頁面加載以后,唯一需要發(fā)送給客戶端的數(shù)據(jù)就是JSON,這將是最有效果的。這個方法能極大性地減少CPU,IO,和Node.js的負載量。
5.使用gzip
許多服務(wù)器和客戶端支持gzip來壓縮請求和應(yīng)答。無論是應(yīng)答客戶端還是向遠程服務(wù)器發(fā)送請求,請確保充分使用它。
6.并行化
試著讓你所有的阻塞操作-向遠程服務(wù)發(fā)送請求,DB調(diào)用,文件系統(tǒng)訪問并行化。這將能減少最慢的阻塞操作的等待時間,而不是所有阻塞操作的等待時間。為了保持回調(diào)和錯誤處理的干凈,我們使用Step來控制流量。
7.Session自由化
領(lǐng)英移動使用Express框架來管理請求/應(yīng)答周期。許多express的例子都包含如下的配置:
app.use(express.session({ secret: "keyboard cat" }));
默認地,session數(shù)據(jù)是存儲在內(nèi)存中的,這會給服務(wù)器增加巨大的開銷,特別是隨著用戶量的增長。你可以使用一個外部session存儲,比如MongoDB或Redis,不過每一個請求將會導(dǎo)致遠程調(diào)用來取得session數(shù)據(jù)的開銷。在可能的情況下,最好的選擇就是在服務(wù)器端存儲所有的無狀態(tài)數(shù)據(jù)。通過不包含上述express配置讓session自由化,你會看到更好的性能。
8.使用二進制模塊
如果可能,用二進制模塊取代JavaScript模塊。例如,當(dāng)我們從用JavaScript寫的SHA模塊轉(zhuǎn)換到Node.js的編譯版本,我們會看到性能的一個大躍進:
// Use built in or binary modules var crypto = require('crypto'); var hash = crypto.createHmac("sha1",key).update(signatureBase).digest("base64");
9.用標準的 V8 JavaScript 取代客戶端庫
許多JavaScript庫都是為了在web瀏覽器上使用而創(chuàng)建的,因為在JavaScript環(huán)境不同時:比如,一些瀏覽器支持forEach,map和reduce這樣的函數(shù),但有些瀏覽器不支持。因此客戶端庫通常用許多低效的代碼來克服瀏覽器的差異。另一方面,在Node.js中,你能確切地知道哪些JavaScript方法是有效的:V8 JavaScript引擎支撐Node.js實現(xiàn)ECMA-262第五版中指定的ECMAScript。直接用標準的V8 JavaScript函數(shù)替代客戶端庫,你會發(fā)現(xiàn)性能得到顯著的提高。
10.讓你的代碼保持小且輕
使用移動設(shè)備會讓訪問速度慢且延遲高,這告訴我們要讓我們的代碼保持小且輕。對于服務(wù)器代碼也保持同樣的理念。偶爾回頭看看你的決定且問自己像這樣的問題:“我們真的需要這個模塊嗎?”,“我們?yōu)槭裁从眠@個框架,它的開銷值得我們使用嗎?”,“我們能用簡便的方法實現(xiàn)它嗎?”。小輕且的代碼通常更高效、快速。
試試看
我們很努力地讓自己的移動應(yīng)用變得快速。在IPhone應(yīng)用,Android應(yīng)用和HTML5移動版本這些平臺上嘗試一下,讓我們知道自己做得怎么樣。
相關(guān)文章
Node.js報錯信息Error:?Cannot?find?module?'XXX'問題及解
這篇文章主要介紹了Node.js報錯信息Error:?Cannot?find?module?'XXX'問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10基于NodeJS的前后端分離的思考與實踐(四)安全問題解決方案
本文就在前后端分離模式的架構(gòu)下,針對前端在Web開發(fā)中,所遇到的安全問題以及應(yīng)對措施和注意事項,并提出解決方案。2014-09-09socket.io學(xué)習(xí)教程之基礎(chǔ)介紹(一)
socket.io提供了基于事件的實時雙向通訊,所以下面這篇文章主要介紹了關(guān)于socket.io的相關(guān)資料,主要介紹了學(xué)習(xí)socket.io的基礎(chǔ)知識,需要的朋友可以參考借鑒,下面來一起看看吧。2017-04-04手把手教你更優(yōu)雅的修改node_modules里的代碼
這篇文章主要給大家介紹了關(guān)于如何更優(yōu)雅的修改node_modules里的代碼的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2023-02-02