極快的node.js:來自LinkedIn移動的10個效能技巧
在之前釋出的文章中,討論了我們是如何測試領英移動堆疊的,包括我們的Node.js移動服務。現在,我們將告訴你我們是如何讓移動服務變得更快的。下面是我們使用Node.js時遵循的10個效能規則:
1. 避免使用同步程式碼
在設計上,Node.js是單執行緒的。為了能讓一個單執行緒處理許多併發的請求,你可以永遠不要讓執行緒等待阻塞,同步或長時間執行的操作。Node.js的一個顯著特徵是:它從上到下的設計和實現都是為了實現非同步。這讓它非常適合用於事件型程式。
不幸的是,還是有可能會發生同步/阻塞的呼叫。例如,許多檔案系統操作同時擁有同步和非同步的版本,比如writeFile和writeFileSync。即使你用程式碼來控制同步方法,但還是有可能不注意地用到阻塞呼叫的外部函式庫。當你這麼做時,對效能的影響是極大的。
// 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在實現時無意地包含了一個同步呼叫來將內容寫入磁碟。如果我們不做效能測試那麼就會很容易忽略這個問題。當以developer box中一個node.js例項來作為標準測試,這個同步呼叫將導致效能從每秒上千次的請求降至只有幾十個。
2.關閉套接字池
Node.js的http客戶端會自動地使用套接字池:預設地,它會限制每臺主機只能有5個套接字。雖然套接字的重複使用可能會讓資源的增加在控制之下,但如果你需要處理許多資料來自於同一主機的併發請求時,將會導致一系列的瓶頸。在這種情況下,增大maxSockets 的值或關閉套接字池是個好主意:
// Disable socket pooling var http = require('http'); var options = {.....}; options.agent = false; var req = http.request(options)
3.不要讓靜態資源使用Node.js
對於css和圖片等靜態資源,用標準的WebServer而不是Node.js。例如,領英移動使用的是nginx。我們同時還利用內容傳遞網路(CDNs),它能將世界範圍內的靜態資拷貝到伺服器上。這有兩個好處:(1)能減少我們node.js伺服器的負載量(2)CDNs可以讓靜態內容在離使用者較近的伺服器上傳遞,以此來減少等待時間。
4.在客戶端渲染
讓我們快速比較一下伺服器渲染和客戶端渲染的區別。如果我們用node.js在伺服器端渲染,對於每個請求我們都會回送像下面這樣的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>
請注意觀察這個頁面所有的內容,除了使用者的名字,其餘都是靜態內容:對於每個使用者和頁面過載內容都是一樣的。因此更有效的作法是讓Node.js僅以JSON形式返回頁面需要的動態內容。
{"name": "John"}
頁面的其餘部分—所有靜態的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>
效能的提升來自於這些地方:如第三點所說,靜態JavaScript模板能通過webserver(比如nginx)在伺服器端提供,或者用更好的CDN來實現。此外,JavaScript模板能快取在瀏覽器中或儲存在本地,所有初始頁面載入以後,唯一需要傳送給客戶端的資料就是JSON,這將是最有效果的。這個方法能極大性地減少CPU,IO,和Node.js的負載量。
5.使用gzip
許多伺服器和客戶端支援gzip來壓縮請求和應答。無論是應答客戶端還是向遠端伺服器傳送請求,請確保充分使用它。
6.並行化
試著讓你所有的阻塞操作-向遠端服務傳送請求,DB呼叫,檔案系統訪問並行化。這將能減少最慢的阻塞操作的等待時間,而不是所有阻塞操作的等待時間。為了保持回撥和錯誤處理的乾淨,我們使用Step來控制流量。
7.Session自由化
領英移動使用Express框架來管理請求/應答週期。許多express的例子都包含如下的配置:
app.use(express.session({ secret: "keyboard cat" }));
預設地,session資料是儲存在記憶體中的,這會給伺服器增加巨大的開銷,特別是隨著使用者量的增長。你可以使用一個外部session儲存,比如MongoDB或Redis,不過每一個請求將會導致遠端呼叫來取得session資料的開銷。在可能的情況下,最好的選擇就是在伺服器端儲存所有的無狀態資料。通過不包含上述express配置讓session自由化,你會看到更好的效能。
8.使用二進位制模組
如果可能,用二進位制模組取代JavaScript模組。例如,當我們從用JavaScript寫的SHA模組轉換到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瀏覽器上使用而建立的,因為在JavaScript環境不同時:比如,一些瀏覽器支援forEach,map和reduce這樣的函式,但有些瀏覽器不支援。因此客戶端庫通常用許多低效的程式碼來克服瀏覽器的差異。另一方面,在Node.js中,你能確切地知道哪些JavaScript方法是有效的:V8 JavaScript引擎支撐Node.js實現ECMA-262第五版中指定的ECMAScript。直接用標準的V8 JavaScript函式替代客戶端庫,你會發現效能得到顯著的提高。
10.讓你的程式碼保持小且輕
使用移動裝置會讓訪問速度慢且延遲高,這告訴我們要讓我們的程式碼保持小且輕。對於伺服器程式碼也保持同樣的理念。偶爾回頭看看你的決定且問自己像這樣的問題:“我們真的需要這個模組嗎?”,“我們為什麼用這個框架,它的開銷值得我們使用嗎?”,“我們能用簡便的方法實現它嗎?”。小輕且的程式碼通常更高效、快速。
試試看
我們很努力地讓自己的移動應用變得快速。在IPhone應用,Android應用和HTML5移動版本這些平臺上嘗試一下,讓我們知道自己做得怎麼樣。
相關文章
- 提升 Node.js 應用效能的 5 個技巧Node.js
- 聘請移動應用開發者的10個技巧
- 10個提升MySQL效能的小技巧MySql
- 還在苦惱移動端的遊戲效能採集?快來使用 Fionna 吧遊戲
- 提升 Web開發效能的 10 個技巧Web
- Web效能優化系列:10個JavaScript效能提升的技巧Web優化JavaScript
- 讓你的 Node.js 應用跑得更快的 10 個技巧Node.js
- 移動遊戲開發的五個技巧遊戲開發
- 讓PHOTOSHOP執行速度變快的10個技巧
- 10個最佳 Node.js 企業應用案例:從 Uber 到 LinkedInNode.js
- google搜尋運算子+101個Google技巧 - Google技巧的終極收集Go
- LinkedIn的Java 11遷移之旅Java
- 關於移動Web效能的5個誤傳Web
- AMP,來自 Google 的移動頁面優化方案Go優化
- 深入解密來自未來的快取-Caffeine解密快取
- 10個Python指令碼來自動化你的日常任務Python指令碼
- CSS效能優化的8個技巧CSS優化
- 6個提升PostgreSQL效能的小技巧SQL
- 5個介面效能提升的通用技巧
- 5 個普通的 Java 效能技巧 - RichardJava
- CSS效能優化的幾個技巧CSS優化
- Java效能優化的5個技巧Java優化
- Apache效能優化的25個技巧Apache優化
- 提高 PostgreSQL 插入效能的 5 個技巧SQL
- 印象最深的一個bug:sessionStorage快取在移動端失效Session快取
- 42個移動端啟動頁面優化技巧優化
- 詳解Facebook的移動廣告投放技巧
- 每個極客都應該知道的Linux技巧Linux
- 10個CSS技巧,極大提升使用者體驗CSS
- 5 個快速的 Node.js 應用效能提示Node.js
- 【Node.js】寫一個資料自動整理成表格的指令碼Node.js指令碼
- 技術更新!10個MySQL效能調優技巧MySql
- 提升Web效能的8個技巧總結Web
- 提升 Python 程式效能的 6 個技巧Python
- 【計算講談社】第四講:自動駕駛,未來的移動智慧載體?自動駕駛
- 移動 Web 開發的10個最佳 JavaScript 框架WebJavaScript框架
- 優化移動遊戲效能 | 來自Unity頂級工程師的效能分析、記憶體與程式碼架構小貼士優化遊戲Unity工程師記憶體架構
- 女性市場崛起:全球有68%的移動遊戲收入來自女性遊戲