NodeJS學習筆記


 

一.概述

Node.js 是一種建立在Google Chrome’s v8 engine上的 non-blocking (非阻塞), event-driven (基於事件的) I/O平台.

以事件驅動為核心,單線程,單進程。Node.js 最大的特點就是采用異步式 I/O 與事件驅動的架構設計。對於高並發的解決方案,傳統的架構是多線程模型,也就是為每個業務邏輯提供一個系統線程,通過系統線程切換來彌補同步式 I/O 調用時的時間開銷。Node.js 使用的是單線程模型,對於所有 I/O 都采用異步式的請求方式,避免了頻繁的上下文切換。Node.js 在執行的過程中會維護一個事件隊列,程序在執行時進入事件循環等待下一個事件到來,每個異步式 I/O 請求完成后會被推送到事件隊列,等待程序進程進行處理。事件驅動機制是Node.js通過內部單線程高效率地維護事件循環隊列來實現的,沒有多線程的資源占用和上下文切換,這意味着面對大規模的http請求,Node.js憑借事件驅動搞定一切。因為Node是基於事件驅動和無阻塞的,所以非常適合處理並發請求。可以通過運行多個Node.js進程的方式來有效利用多個CPU。

 

二.Node.js選擇的異步I/O方案

1.在Linux下,node.js靠libev和libeio配合使用來實現異步I/O。

(1).什么是libev?

• libev是一個事件驅動庫,提供高性能事件循環

• 主要用於事件驅動的網絡編程

(2).什么是libeio?

libeio為C提供異步版本的POSIX API

• 主要提供文件I/O操作

• 異步操作通過線程實現

• libeio僅依賴pthread,跨平台能力非常好

• 可以和任何事件庫配合使用,比如libev 。

(3).為什么不用libev實現異步文件操作?

對於Regular File 來說,是不能夠用采用 poll/epoll 的,即O_NOBLOCK 方式對於傳統文件句柄是無效的,也就是說我們的 open ,read, mkdir 之類的Regular File操作必定會導致阻塞.

 

2.Windows有一種獨有的內核異步IO方案:IOCP。IOCP的思路是真正的異步I/O方案,調用異步方法,然后等待I/O完成通知。IOCP內部依舊是通過線程實現,不同在於這些線程由系統內核接手管理。IOCP的異步模型與Node.js的異步調用模型已經十分近似。

     

3.由於Windows平台和*nix平台的差異,Node.js提供了libuv來作為抽象封裝層,使得所有平台兼容性的判斷都由這一層次來完成,保證上層的Node.js與下層的libeio/libev及IOCP之間各自獨立。Node.js在編譯期間會判斷平台條件,選擇性編譯unix目錄或是win目錄下的源文件到目標程序中。

對於 POSIX①操作系統,libuv 通過封裝 libev 和 libeio 來利用 epoll 或 kqueue。而在 Windows 下,libuv 使用了 Windows 的 IOCP(Input/Output Completion Port,輸入輸出完成端口)機制,以在不同平台下實現同樣的高性能。

① POSIX(Portable Operating System Interface)是一套操作系統 API 規范。一般而言,遵守 POSIX 規范的操作系統指的是 UNIX、Linux、Mac OS X 等。

arch

 

下面是Node.JS架構示意圖

1-2

 

三.異步式 I/O 與事件驅動

Node.js 的異步機制是基於事件的,所有的磁盤 I/O、網絡通信、數據庫查詢都以非阻塞的方式請求,返回的結果由事件循環來處理。圖1-1 描述了這個機制。Node.js 進程在同一時刻只會處理一個事件,完成后立即進入事件循環檢查並處理后面的事件。這樣做的好處是,CPU 和內存在同一時間集中處理一件事,同時盡可能讓耗時的 I/O 操作並行執行。對於低速連接攻擊,Node.js 只是在事件隊列中增加請求,等待操作系統的回應,因而不會有任何多線程開銷,很大程度上可以提高 Web 應用的健壯性,防止惡意攻擊。

1-1

圖1-1 事件循環

 

以在Windows平台下的實現中,啟動Node.js時,便創建了一個基於IOCP的事件循環loop,並一直處於執行狀態。

uv_run(uv_default_loop());

每次循環中,它會調用IOCP相關的GetQueuedCompletionStatus方法檢查是否線程池中有執行完的請求,如果存在,poll操作會將請求對象加入到loop的pending_reqs_tail屬性上。 另一邊這個循環也會不斷檢查loop對象上的pending_reqs_tail引用,如果有可用的請求對象,就取出請求對象的result屬性作為結果傳遞給oncomplete_sym執行,以此達到調用JavaScript中傳入的回調函數的目的。 至此,整個異步I/O的流程完成結束。

事件循環和請求對象構成了Node.js的異步I/O模型的兩個基本元素,這也是典型的消費者生產者場景。在Windows下通過IOCP的GetQueuedCompletionStatus、PostQueuedCompletionStatus、QueueUserWorkItem方法與事件循環實。對於*nix平台下,這個流程的不同之處在與實現這些功能的方法是由libeio和libev提供。

 

四.多線程阻塞服務器 vs 事件驅動、無阻塞服務器

clipboard

clipboard[1]

 

 

參考:

 

1. http://www.nodebeginner.org/index-zh-cn.html Node入門

2. http://www.infoq.com/cn/articles/what-is-nodejs  深入淺出Node.js(一):什么是Node.js

3. http://www.infoq.com/cn/articles/nodejs-asynchronous-io  深入淺出Node.js(五):初探Node.js的異步I/O實現

4. http://www.ituring.com.cn/article/5779  異步式 I/O 與事件驅動 《Node.js開發指南》

5. http://www.codingguy.net/?p=195  Node.js代碼閱讀筆記之libeio

6.PM編程語言與架構專場 Node.js簡介 Chinese.pdf

7.nodejs異步_原理和缺陷.pdf


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM