node.js学习总结
生活随笔
收集整理的這篇文章主要介紹了
node.js学习总结
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
NodeJS介紹
1.概述:? ? ? Node.js是基于Chrome JavaScript運(yùn)行時(shí)建立的一個(gè)平臺(tái),實(shí)際上它是對(duì)Google Chrome V8引擎
進(jìn)行了封裝,它主要用于創(chuàng)建快速的、可擴(kuò)展的網(wǎng)絡(luò)應(yīng)用。Node.js采用事件驅(qū)動(dòng)和非阻塞I/O模型,使
其變得輕微和高效,非常適合構(gòu)建運(yùn)行在分布式設(shè)備的數(shù)據(jù)密集型實(shí)時(shí)應(yīng)用。
? ? ? 運(yùn)行于瀏覽器的Javascript,瀏覽器就是Javascript代碼的解析器,而Node.js則是服務(wù)器端JS的
代碼解析器,存于服務(wù)器端的JS代碼由Node.js來(lái)解析和應(yīng)用。
? ? ? JS解析器只是JS代碼運(yùn)行的一種環(huán)境,瀏覽器是JS運(yùn)行的一種環(huán)境,瀏覽器為JS提供了操作DOM對(duì)
象和window對(duì)象等接口。Node.js也是JS的一種運(yùn)行環(huán)境,node.js為JS提供操作文件、創(chuàng)建http服務(wù)、
創(chuàng)建TCP、UDP服務(wù)等接口,所以Node.js可以完成其他后臺(tái)語(yǔ)言能完成的工作。
2.交互式運(yùn)行環(huán)境:PEPL
? ? ? Node.js提供了一個(gè)交互式運(yùn)行環(huán)境,通過這個(gè)環(huán)境,可以立即執(zhí)行JS代碼,使用方法類似于
Chrome瀏覽器中Firebug插件中的Console。
? ? ? 在Linux環(huán)境進(jìn)入終端后,屬于"node"或者“nodejs”進(jìn)入Node.js的交互式運(yùn)行環(huán)境,Ctrl+d可
以退出此環(huán)境。
? ? ? 查看系統(tǒng)中安裝的Node.js版本:node -v or nodejs -v
? ? ? 運(yùn)行JS文件,eg:node file.js or nodejs file.js
3.Node.js模塊和包
? ? ? a.模塊
? ? ? ? ?Node.js官方提供了很多模塊,這些模塊分別實(shí)現(xiàn)了一種功能,如操作文件模塊fs,構(gòu)建http服
務(wù)模塊的http等,每個(gè)模塊都是一個(gè)JS文件,當(dāng)然也可以自己編 ? 寫模塊。
? ? ? 2.包
? ? ? ? ? 包可以將多個(gè)具有依賴關(guān)系的模塊組織在一起,封裝多個(gè)模塊,以方便管理。Node.js采用了
CommonJS規(guī)范,根據(jù)CommonJS規(guī)范規(guī)定,一個(gè)JS文件就是 一個(gè)模塊,而包是一個(gè)文件夾,包內(nèi)必須包含
一個(gè)JSON文件,命名package.json。一般情況下,包內(nèi)bin文件夾存放二進(jìn)制文件,包內(nèi)的lib文件夾存
放JS文件,包內(nèi)的doc文件夾存放文檔,包內(nèi)的test文件夾存放單元測(cè)試。package.json文件中需要包含
的字段及包的使用。
? ? ? 3.npm包管理工具
? ? ? ? ?npm是node.js的包管理工具,npm定義了包依賴關(guān)系標(biāo)準(zhǔn),我們使用npm主要用來(lái)下載第三方包
和管理本地下載的第三方包。
========
為什么我要用 Node.js? 案例逐一介紹
介紹
JavaScript 高漲的人氣帶來(lái)了很多變化,以至于如今使用其進(jìn)行網(wǎng)絡(luò)開發(fā)的形式也變得截然不同了。就
如同在瀏覽器中一樣,現(xiàn)在我們也可以在服務(wù)器上運(yùn)行 JavaScript ,從前端跨越到后端,這樣巨大的
反差讓人難以想象,因?yàn)閮H僅在幾年前 Javascript 還如同 Flash 或者 Java applet 那樣嵌入網(wǎng)頁(yè)在
沙箱環(huán)境中運(yùn)行。
在深入Node.js之前,你可能需要閱讀和了解使用跨棧式JavaScript(JavaScript across the stack)
帶來(lái)的好處,它統(tǒng)一了編程語(yǔ)言和數(shù)據(jù)格式(JSON),讓你能最佳地重用開發(fā)人員資源。由于這更多的
是關(guān)于 JavaScript 的特點(diǎn),這里就不過多討論它。但它確實(shí)是一個(gè)讓人在開發(fā)環(huán)節(jié)中使用 Node 的關(guān)
鍵的優(yōu)點(diǎn)。
正如維基百科 所說(shuō):“Node.js 是谷歌 V8 引擎、libuv平臺(tái)抽象層 以及主體使用 Javscript 編寫的
核心庫(kù)三者集合的一個(gè)包裝外殼。” 除此之外,值得注意的是,Node.js 的作者瑞恩·達(dá)爾 (Ryan?
Dahl) 的目標(biāo)是創(chuàng)建具有實(shí)時(shí)推送能力的網(wǎng)站。在 Node.js 中,他給了開發(fā)者一個(gè)使用事件驅(qū)動(dòng)來(lái)實(shí)現(xiàn)
異步開發(fā)的優(yōu)秀解決方案。(注:V8是谷歌開發(fā)的,目前公認(rèn)最快的 Javascript 解析引擎,libuv 是
一個(gè)開源的、為 Node 定制而生的跨平臺(tái)的異步 IO 庫(kù)。)
簡(jiǎn)而言之:Node.js 在實(shí)時(shí)的 Web應(yīng)用上采用了基于 WebSocket 的推送技術(shù)。這意味著什么樣的革命性
?Well,在經(jīng)過了20多年的基于無(wú)狀態(tài)的請(qǐng)求-返機(jī)制的無(wú)狀態(tài)交互之后,我們終于有了實(shí)時(shí)的,雙向連
接的web應(yīng)用,客戶端和服務(wù)器端都可以發(fā)起通信,能夠自由地交換數(shù)據(jù)。與此形成鮮明對(duì)比的是傳統(tǒng)的?
web響應(yīng)模式,客戶端總是主動(dòng)發(fā)起通信而服務(wù)端被動(dòng)返回。此外,這些都是基于運(yùn)行在標(biāo)準(zhǔn)80端口上的
開放Web組件(HTML、CSS和JS)。
可能有人會(huì)說(shuō),我們已經(jīng)使用 Flash 和 Java Applet 的形式很多年了——但實(shí)際上,這些方式只是使
用網(wǎng)絡(luò)將數(shù)據(jù)傳遞到客戶端上的沙箱環(huán)境。他們都是隔離運(yùn)行的,而且經(jīng)常操作到需要額外的權(quán)限之類
的非標(biāo)準(zhǔn)端口。
憑借其獨(dú)特的優(yōu)勢(shì),Node.js的現(xiàn)在已經(jīng)在許多著名公司的產(chǎn)品中起到了關(guān)鍵作用。
在這篇文章中,我們不僅將討論這些優(yōu)勢(shì)是如何實(shí)現(xiàn)的,而且也會(huì)討論為什么你使用 Node.js 來(lái)替代一
些經(jīng)典的Web應(yīng)用程序模型。
Node.js 是如何工作的?
Node.js 的主要思路是:使用非阻塞的,事件驅(qū)動(dòng)的 I/O 操作來(lái)保持在處理跨平臺(tái) (across?
distributed devices) 數(shù)據(jù)密集型實(shí)時(shí)應(yīng)用時(shí)的輕巧高效。這聽起來(lái)有點(diǎn)繞口。
它的真正含義是,Node.js 不是一個(gè)即將主導(dǎo)Web開發(fā)的世界的銀彈級(jí)的平臺(tái)。相反,它是一個(gè)滿足特別
需求的平臺(tái)。你肯定不會(huì)希望使用 Node.js 去做 CPU密集型操作。事實(shí)上,使用它進(jìn)行繁重的計(jì)算等于
摒棄 Node 幾乎所有的優(yōu)點(diǎn)。Node 真正的亮點(diǎn)在于建設(shè)高性能,高擴(kuò)展性的互聯(lián)網(wǎng)應(yīng)用——因?yàn)樗軌?
處理龐大的并且高吞吐量的并發(fā)連接。
它的工作原理是相當(dāng)有趣的。傳統(tǒng)的網(wǎng)絡(luò)服務(wù)技術(shù),是每個(gè)新增一個(gè)連接(請(qǐng)求)便生成一個(gè)新的線程
,這個(gè)新的線程會(huì)占用系統(tǒng)內(nèi)存,最終會(huì)占掉所有的可用內(nèi)存。而 Node.js 僅僅只運(yùn)行在一個(gè)單線程中
,使用非阻塞的異步 I/O 調(diào)用,所有連接都由該線程處理,在 libuv 的加分下,可以允許其支持?jǐn)?shù)萬(wàn)
并發(fā)連接(全部掛在該線程的事件循環(huán)中)。
toptal-blog-1_B
做一個(gè)簡(jiǎn)單的計(jì)算: 假設(shè)是普通的Web程序,新接入一個(gè)連接會(huì)占用 2M 的內(nèi)存,在有 8GB RAM的系統(tǒng)上
運(yùn)行時(shí), 算上線程之間上下文切換的成本,并發(fā)連接的最大理論值則為 4000 個(gè)。這是在傳統(tǒng) Web服務(wù)
端技術(shù)下的處理情況。而 Node.js 則達(dá)到了約 1M 一個(gè)并發(fā)連接的拓展級(jí)別 (相關(guān)證明).
當(dāng)然,在所有客戶端的請(qǐng)求共享單一線程時(shí)也會(huì)有問題, 這也是一個(gè)編寫 Node.js 應(yīng)用的潛在缺陷. 首
先, 大量的計(jì)算可能會(huì)使得 Node 的單線程暫時(shí)失去反應(yīng), 并導(dǎo)致所有的其他客戶端的請(qǐng)求一直阻塞,?
直到計(jì)算結(jié)束才恢復(fù)正常。 其次,開發(fā)人員需要非常小心,不要讓一個(gè) Exception 阻塞核心的事件循
環(huán),因?yàn)檫@將導(dǎo)致 Node.js 實(shí)例的終止(實(shí)際上就是程序崩潰)。( 筆者注:如 PHP 中某個(gè)頁(yè)面掛掉
是不會(huì)影響網(wǎng)站運(yùn)行的,但是 Nodejs 是一個(gè)線程一個(gè)線程來(lái)處理所有的鏈接,所以不論是計(jì)算卡了或
者是被異常阻塞了都可能會(huì)影響到其他所有的鏈接。解決方案在稍后討論。)
用來(lái)避免異常拋出時(shí)中斷進(jìn)程的方法是將異常使用回調(diào)傳遞出去(而不是拋出他們,就像在其他環(huán)境中
一樣)。即使一些未處理的異常阻塞了程序,依舊有多種應(yīng)對(duì)的解決方案,而且也有很多可用于監(jiān)視?
Node 進(jìn)程來(lái)執(zhí)行必要的崩潰后恢復(fù)工作的策略和工具(雖然你將無(wú)法恢復(fù)用戶的 Session ),最常見
的是使用 Forever 模塊,或者采用其他的外部系統(tǒng)工具如 upstart and monit。
NPM: The Node Package Manager
當(dāng)我們討論 Node.js 的時(shí)候,一個(gè)絕對(duì)不應(yīng)該忽略地方就是默認(rèn)內(nèi)置的模塊管理工具 —— NPM。 其靈
感來(lái)源與 Ruby Gems(具有版本和依賴管理功能,可以通過在線資料庫(kù)便捷安裝可重用的組件的管理工
具)。
一個(gè)完整的公用模塊列表可以在 NPM 的網(wǎng)站上找到(https:://npmjs.org/),或者通過使用與?
Node.js 一同安裝的 NPM CLI 工具放問到。該模塊的生態(tài)系統(tǒng)向所有人開放,任何人都可以發(fā)布自己的
模塊,所有的模塊都可以在 NPM 資料庫(kù)中找到。你可以在 http://howtonode.org/introduction-to-
npm 頁(yè)面找到 NPM 的一個(gè)簡(jiǎn)要介紹(有點(diǎn)舊,但依舊能看)。
目前非常流行的一些 NPM 模塊有:
express – Express.js,是一個(gè)簡(jiǎn)潔而靈活的 node.js Web應(yīng)用框架, 并且已經(jīng)是現(xiàn)在大多數(shù) Node.js?
應(yīng)用的標(biāo)準(zhǔn)框架,你已經(jīng)可以在很多 Node.js 的書籍中看到它了。
connect – Connect 是一個(gè) Node.js 的 HTTP 服務(wù)拓展框架,提供一個(gè)高性能的“插件”集合,以中
間件聞名,是 Express 的基礎(chǔ)部分之一。
socket.io 和 sockjs – 目前服務(wù)端最流行的兩個(gè) websocket 組件。
Jade – 流行的模板引擎之一,并且是 Express.js 的默認(rèn)模板引擎。其靈感來(lái)源于 HAML。
mongo 和 mongojs – 封裝了 MongoDB 的的各種 API,不過筆者平常工作用的是 mongoose 也很推薦。
redis – Redis 的客戶端函數(shù)庫(kù).
coffee-script – CoffeeScript 編譯器,允許開發(fā)者使用 Coffee 來(lái)編寫他們的 Node.js 程序。
underscore (lodash, lazy) – 最流行的 JavaScript 工具庫(kù) , 用于 Node.js 的封裝包,以及兩個(gè)采
取略有不同的實(shí)現(xiàn)方法來(lái)獲得更好性能的同行。
forever – 可能是用來(lái)確保 node 腳本持續(xù)運(yùn)行的最流行的工具。
還有很多好的模塊,這里就不一一列舉了(希望沒有冒犯到?jīng)]列舉的)。
Node.js 應(yīng)該用在什么地方
聊天
聊天是最典型的多用戶實(shí)時(shí)交互的應(yīng)用。從 IRC 開始,有許多開源或者不開源的協(xié)議都運(yùn)行在非標(biāo)準(zhǔn)端
口上,而現(xiàn)在,使用 Node.js 則可以解決這些問題——在標(biāo)準(zhǔn)的80端口運(yùn)行 WebSockets。
聊天應(yīng)用程序是最能體現(xiàn) Node.js 優(yōu)點(diǎn)的例子:輕量級(jí)、高流量并且能良好的應(yīng)對(duì)跨平臺(tái)設(shè)備上運(yùn)行密
集型數(shù)據(jù)(雖然計(jì)算能力低)。同時(shí),聊天也是一個(gè)非常值得學(xué)習(xí)的用例,因?yàn)樗芎?jiǎn)單,并且涵蓋了
目前為止一個(gè)典型的 Node.js 會(huì)用到的大部分解決方案。
讓我們?cè)囍鴣?lái)描繪它如何工作。
在最簡(jiǎn)單的情況下,我們布置了一個(gè)聊天室在我們的網(wǎng)站上,用戶可以在上面發(fā)消息,當(dāng)然是一對(duì)多的
形式。例如,假設(shè)總共有三個(gè)人連接到我們的網(wǎng)站上。
在服務(wù)端這邊, 我們有一個(gè)使用 Express.js 搭建的簡(jiǎn)單站點(diǎn),該站點(diǎn)實(shí)現(xiàn)了兩件事 1) 處理路徑為?
‘/’ 的GET請(qǐng)求時(shí),下發(fā)包括一個(gè)留言板以及一個(gè)發(fā)送信息的 ‘發(fā)送’ 按鈕的頁(yè)面 2) 一個(gè)監(jiān)聽客戶
端發(fā)送新消息的 websockets 服務(wù)。
在客戶端這邊,我們有一個(gè) HTML 頁(yè)面,上面有個(gè)兩個(gè) js 方法,一個(gè)是用于觸發(fā)事件的 “發(fā)送” 按
鈕,這會(huì)把把輸入的消息通過 webscoket 發(fā)送,另一個(gè)方法是用 webscoket 在客戶端上監(jiān)聽服務(wù)端來(lái)
的推送(例如,其他用戶發(fā)送的消息)。
當(dāng)有一個(gè)客戶端發(fā)送消息的時(shí)候,發(fā)生的事情是:
瀏覽器上,點(diǎn)擊發(fā)送按鈕觸發(fā)了 js 函數(shù),將輸入框中的文字通過 websocket 消息發(fā)送到服務(wù)器的?
websocket 客戶端(頁(yè)面初始化加載的時(shí)候連接的)。
服務(wù)端的 websocket 組件收到 消息,然后通過廣播方法轉(zhuǎn)發(fā)到其他所有連接的客戶端。
通過頁(yè)面上運(yùn)行的 websocket 客戶端組件,所有的客戶端都能收到這條推送的新消息。接著 js 處理函
數(shù)可以把這個(gè)消息添加到文字框內(nèi)。
toptal-blog-2_B
這是一個(gè)最簡(jiǎn)單的例子。如果要更好的解決方案,你可以使用 Redis 數(shù)據(jù)庫(kù)做一個(gè)簡(jiǎn)單的緩存。在一個(gè)
更高級(jí)的解決方案中,你可能需要一個(gè)消息路由來(lái)專門處理消息隊(duì)列,并且需要一個(gè)更強(qiáng)健的發(fā)送機(jī)制
,比如發(fā)送的時(shí)候覆蓋上暫時(shí)離線的用戶或者為離線的注冊(cè)用戶存儲(chǔ)尚未接收的消息等等。但是不論你
做了怎么樣的改進(jìn),Node.js 都將遵循一個(gè)基本原則:響應(yīng)事件,處理多個(gè)并發(fā)連接,并保持流動(dòng)性的
用戶體驗(yàn)。
對(duì)象數(shù)據(jù)庫(kù)接口(API ON TOP OF AN OBJECT DB)
盡管,Node.js 確實(shí)非常擅長(zhǎng)實(shí)時(shí)交互的應(yīng)用,同時(shí)它也十分適合通過對(duì)象數(shù)據(jù)庫(kù)(object DB)來(lái)查詢
數(shù)據(jù)(如 MongoDB)。以 JSON 格式存儲(chǔ)的數(shù)據(jù)允許 Node.js 直接處理,不需要糾結(jié)數(shù)據(jù)轉(zhuǎn)換和匹配的
問題。
舉個(gè)例子,如果你正在使用 Rails,你會(huì)將 JSON 數(shù)據(jù)轉(zhuǎn)成 二進(jìn)制的 model,當(dāng)數(shù)據(jù)再被?
Backbone.js, Angular.js 或者 jQuery AJAX 之類的調(diào)用又要轉(zhuǎn)回 JSON。如果是 Nodejs 的話,你可
以通過一個(gè) REST API 簡(jiǎn)單的導(dǎo)出 JSON 對(duì)象以供客戶端使用。另外,從數(shù)據(jù)庫(kù)讀寫時(shí)候如果使用的是?
MongoDB 的話,你也不用擔(dān)心的 JSON 與任何數(shù)據(jù)之間的格式問題。總之,你可以避免多元的數(shù)據(jù)轉(zhuǎn)換
問題,不論是在客戶端、服務(wù)端還是數(shù)據(jù)庫(kù)。
隊(duì)列輸入
如果你正在接收一個(gè)高量并發(fā)的數(shù)據(jù),你的數(shù)據(jù)庫(kù)可能會(huì)成為你處理的瓶頸。正如上面的描述,Node.js?
可以輕松的處理并發(fā)連接。 但是,由于數(shù)據(jù)庫(kù)操作是一個(gè)阻塞的操作(在這種情況下),這就是麻煩的
地方。Node.js的解決方案是,在數(shù)據(jù)真正的寫入之前就承認(rèn)客戶端的數(shù)據(jù)是真實(shí)的。
用這種方法,在高負(fù)載的時(shí)候系統(tǒng)繼續(xù)維持它的響應(yīng),這在當(dāng)客戶端不需要嚴(yán)格確認(rèn)一個(gè)數(shù)據(jù)是否成功
的被寫入時(shí)特別有用。典型的例子包括:日志記錄或者用戶跟蹤數(shù)據(jù)(user-tracking data)的記錄,
這會(huì)被分批處理并且在稍后才使用;同時(shí)也包括最終一致性(so, 常用于 NoSQL)可以接受,不需要立
即反應(yīng)的操作(例如 Facebook 上更新點(diǎn)贊的數(shù)目)。
數(shù)據(jù)通過某些緩存或者消息隊(duì)列的基礎(chǔ)組件(例如 RabbitMQ, ZeroMQ)進(jìn)入隊(duì)列,并且通過一個(gè)獨(dú)立的
數(shù)據(jù)庫(kù)批量寫入進(jìn)程來(lái)一一消化,或者通過一個(gè)更高性能的計(jì)算密集型后端服務(wù)來(lái)進(jìn)行處理。其他的語(yǔ)
言/框架也可以實(shí)現(xiàn)相似的操作,但在相同的配置下是達(dá)不到 nodejs 的高吞吐量與高并發(fā)。
toptal-blog-3_B
簡(jiǎn)單的說(shuō):使用 Node,你可以把數(shù)據(jù)庫(kù)操作扔到一邊并在稍后處理它們,假設(shè)他們成功了一樣繼續(xù)執(zhí)行
下去。(筆者注:在開發(fā)中通常的情況通常是,種耗時(shí)的操作通過回調(diào)函數(shù)來(lái)異步處理,主線程繼續(xù)往
下執(zhí)行)
數(shù)據(jù)流
在較為傳統(tǒng)的網(wǎng)絡(luò)平臺(tái)上,HTTP 的請(qǐng)求和響應(yīng)更像是孤立的事件;然而事實(shí)上,他們都是數(shù)據(jù)流。這一
觀察結(jié)果在 Nodejs 上可以用來(lái)建立一些很酷的功能。因?yàn)閿?shù)據(jù)通以流的形式接收,而我們可以在網(wǎng)站
上在線處理正在上傳中的文件。這樣的話,就可以實(shí)現(xiàn)實(shí)時(shí)的音頻和視頻編碼,以及在不同數(shù)據(jù)源之間
進(jìn)行代碼(代理見下一段)。
(筆者注:Node 有代替如 apache 這樣的 webserver 處理數(shù)據(jù),所以開發(fā)者可以直接收到客戶端一份
一份上傳的數(shù)據(jù),并實(shí)時(shí)處理。上面這段話聽起來(lái)有點(diǎn)抽象,不過各位可以簡(jiǎn)單的想象一下不需要開 YY?
或者 QQ,打開網(wǎng)頁(yè)就能進(jìn)行語(yǔ)音視頻的功能。)
代理
Node.js 可以通過異步的方式處理大量的并發(fā)連接,所以很容易作為服務(wù)端的代理來(lái)使用。這在與不同
響應(yīng)時(shí)間的不同服務(wù)之間進(jìn)行代理,或者是收集來(lái)自多個(gè)來(lái)源的數(shù)據(jù)時(shí)尤其有用。
舉個(gè)例子:考慮一個(gè)服務(wù)器端的應(yīng)用程序和第三方資源進(jìn)行通信以更新自不同來(lái)源的數(shù)據(jù),或者將服務(wù)
端上的一些圖像和視頻資源存儲(chǔ)到第三方云服務(wù)。
雖然專用代理服務(wù)器確實(shí)存在,但是如果你還沒有專用的代理服務(wù)器,或者你需要一個(gè)本地開發(fā)的解決
方案,那么使用 Node 來(lái)做代理可能是更好的選擇。關(guān)于這個(gè)解決方案,我的意思是指當(dāng)你在開發(fā)的時(shí)
候,你可以使用Node.js的開發(fā)環(huán)境搭建一個(gè)服務(wù)來(lái)處理對(duì)資源和代理的請(qǐng)求,而在生產(chǎn)環(huán)境下,你可以
使用專用的代理服務(wù)(比如nginx,HAProxy等)來(lái)處理這些交互。
股票操盤手的儀表盤
讓我們繼續(xù)討論應(yīng)用程序這塊。實(shí)時(shí)網(wǎng)絡(luò)的解決方案可以很輕松的實(shí)現(xiàn)證券交易軟件——用于跟蹤股票
的價(jià)格,執(zhí)行計(jì)算、做技術(shù)分析,同時(shí)生成報(bào)表。
使用一個(gè)實(shí)時(shí)的的基于網(wǎng)頁(yè)的解決方案,將會(huì)允許操盤手輕松的切換工作軟件以及工作地點(diǎn)。相信不久
,我們或許會(huì)在 佛羅里達(dá)州、伊維薩島又或者是巴厘島的海灘上看到他們。
應(yīng)用監(jiān)聽儀盤表
另一種常見的用例中,使用 Node+Web+Socket 非常適合:跟蹤網(wǎng)站訪問者并且可視化實(shí)時(shí)它們之間的實(shí)
時(shí)交互。 (如果你有興趣,可以去看看 Hummingbird)
你可能需要采集用戶的實(shí)時(shí)狀態(tài), 或者甚至當(dāng)他們到達(dá)渠道中某個(gè)特定的點(diǎn)時(shí), 打開一個(gè)交流頻道, 通
過有針對(duì)性的互動(dòng)介紹移動(dòng)到下一個(gè)階段. (如果你感興趣的話,推薦你看看 CANDDi)
想象一下,如果你知道你的訪客的實(shí)時(shí)操作,并能夠形象化地看到他們的交互,這將對(duì)你的業(yè)務(wù)帶來(lái)多
大的提升。隨著實(shí)時(shí)的、雙向 socket 通信的 Node.js ,現(xiàn)在你可以做到了。
系統(tǒng)監(jiān)控儀表
現(xiàn)在,讓我們看看事情的基礎(chǔ)設(shè)施方面。想象一下,比如,希望為其用戶提供服務(wù)監(jiān)控頁(yè)面(例如,
GitHub上的狀態(tài)頁(yè))的 SaaS 運(yùn)營(yíng)商 。通過 Node.js 的事件循環(huán),我們可以創(chuàng)建一個(gè)基于 Web 的功能
強(qiáng)大的儀表板,以異步方式檢查服務(wù)狀態(tài)并且使用的 WebSockets 將數(shù)據(jù)推送到客戶端。
內(nèi)部(公司內(nèi)部)和公共服務(wù)的狀態(tài)都可以使用該項(xiàng)技術(shù)實(shí)現(xiàn)實(shí)時(shí)的上報(bào)。讓我們把這一想法延伸的遠(yuǎn)
一點(diǎn),試著想象一個(gè)電信運(yùn)營(yíng)商中網(wǎng)絡(luò)運(yùn)營(yíng)中心(NOC)的監(jiān)控應(yīng)用,云/網(wǎng)絡(luò)/服務(wù)器運(yùn)營(yíng)商,或者一些
金融機(jī)構(gòu),全都運(yùn)行在這個(gè)由 Node.js 和 WebSocket 組成的應(yīng)用上,而不是 Java 和/或 Java Applet
。
注意:不要嘗試使用 Node 打造硬實(shí)時(shí)系統(tǒng)(即,響應(yīng)時(shí)間要求一致的系統(tǒng))。 Erlang是可能是該類應(yīng)
用程序的更好的選擇。
什么地方可以使用 Node.js
服務(wù)端 WEB 應(yīng)用
通過 Node.js 使用 Express.js 也可以用來(lái)創(chuàng)建服務(wù)端上的典型的網(wǎng)頁(yè)應(yīng)用。然而,雖然有可能,使用?
Node.js 來(lái)進(jìn)行請(qǐng)求+響應(yīng)的形式來(lái)呈現(xiàn) HTML 并不是最典型的用例。有人贊成也有人反對(duì)這一做法。這
里有一些看法以供參考:
優(yōu)點(diǎn):
如果你不需要進(jìn)行 CPU密集型計(jì)算,你可以從頭到尾甚至是數(shù)據(jù)庫(kù)(比如 MongoDB)都使用 Javascript?
來(lái)開發(fā)。這顯著地減輕了開發(fā)工序(包括成本)。
對(duì)于一個(gè)使用 Node.js 作為服務(wù)端的單頁(yè)應(yīng)用或者 websocket 應(yīng)用,爬蟲可以收到一個(gè)完全 HTML 呈
現(xiàn)的響應(yīng),這是更為SEO友好的。
缺點(diǎn):
任何CPU密集型的計(jì)算都將阻礙 Node.js 的反應(yīng),所以使用多線程的平臺(tái)是一個(gè)更好的方法。或者,您
也可以嘗試向外擴(kuò)展的計(jì)算[*]。
Node.js 使用關(guān)系型數(shù)據(jù)庫(kù)依舊十分痛苦(詳細(xì)見下方)。拜托了,如果你想執(zhí)行關(guān)系型數(shù)據(jù)操作,請(qǐng)
考慮別的環(huán)境:Rails, Django 甚至 ASP.NET MVC 。。。。
【*】另一種解決方案是,為這些CPU密集型的計(jì)算建立一個(gè)高度可擴(kuò)展的MQ支持的環(huán)境與后端處理,以
保持 Node 作為一個(gè)前臺(tái)專員來(lái)異步處理客戶端請(qǐng)求。
Node.js 不應(yīng)該在什么地方使用
使用關(guān)系型數(shù)據(jù)庫(kù)的服務(wù)端 WEB 應(yīng)用
對(duì)比 Node.js 上的 Express.js 和 Ruby on Rails,當(dāng)你使用關(guān)系型數(shù)據(jù)庫(kù)的時(shí)候請(qǐng)毫不猶豫的選擇后
者。
Node.js 的關(guān)系數(shù)據(jù)庫(kù)工具仍處于早期階段,目前還沒有成熟到讓人能夠愉快地使用它。而與此同時(shí),
Rails天生自帶了數(shù)據(jù)訪問組件,連同DB schema遷移的支持工具和一些Gems(一語(yǔ)雙關(guān),一指這些如同
珍寶的工具,二指ruby的gems程序包)。Rails和它的搭檔框架們擁有非常成熟且被證明了的活動(dòng)記錄(
Active Record)或數(shù)據(jù)映射(Data Mapper)的數(shù)據(jù)訪問層的實(shí)現(xiàn),而這些是當(dāng)你在使用純JavaScript
來(lái)復(fù)制這些應(yīng)用的時(shí)候會(huì)非常想要使用的東西。
不過,如果你真的傾向于全部使用 JS(并且做好可能抓狂的準(zhǔn)備),那么請(qǐng)繼續(xù)關(guān)注 Sequelize 和?
Node ORM2 ,雖然這兩者仍然不成熟的,但他們最終會(huì)迎頭趕上。
[*] 使用 Node 光是作為前端而 Rails 做后端來(lái)連接關(guān)系型數(shù)據(jù)庫(kù),這是完全有可能也并不少見的。(
筆者注:國(guó)外有種說(shuō)法,PHP這一類程序員也可以算作是前端)
繁重的服務(wù)端的計(jì)算和處理
當(dāng)涉及到大量的計(jì)算,Node.js 就不是最佳的解決方案。你肯定不希望使用 Node.js 建立一個(gè)斐波那契
數(shù)的計(jì)算服務(wù)。一般情況下,任何 CPU密集型操作 會(huì)削弱掉 Node通過事件驅(qū)動(dòng), 異步 I/O 模型等等
帶來(lái)的在吞吐量上的優(yōu)勢(shì),因?yàn)楫?dāng)線程被非異步的高計(jì)算量占用時(shí)任何傳入的請(qǐng)求將被阻塞。
正如前面所說(shuō),Node.js 是單線程的,只使用一個(gè)單一的CPU核心。至于,涉及到服務(wù)器上多核并發(fā)處理
,Node 的核心團(tuán)隊(duì)已經(jīng)使用 cluster 模塊的形式在這一方面做了一些工作 (參考:
http://nodejs.org/api/cluster.html)。當(dāng)然,您也可以很容易的通過 nginx 的反向代理運(yùn)行多個(gè)?
Node.js 的服務(wù)器實(shí)例來(lái)避免單一線程阻塞的問題。
關(guān)于集群(clustering) ,你應(yīng)該將所有繁重的計(jì)算轉(zhuǎn)移到更合適的語(yǔ)言寫的后臺(tái)進(jìn)程來(lái)處理,同時(shí)讓他
們通過像 RabbitMQ 那樣通過消息隊(duì)列服務(wù)器來(lái)進(jìn)行通信。
即使你的后臺(tái)處理可能最初運(yùn)行在同一臺(tái)服務(wù)器上時(shí)看不出什么優(yōu)點(diǎn),但是這樣的做法具有非常高的可
擴(kuò)展性的潛力。這些后臺(tái)處理服務(wù)可以容易地分割出去,作為單獨(dú)的 worker 服務(wù)器,而不需要配置入
口 web服務(wù)器的負(fù)載。
當(dāng)然,你也可以在其他語(yǔ)言平臺(tái)上用同樣的方法,但使用 Node.js 你可以得到很高的吞吐量,每個(gè)請(qǐng)求
都作為一個(gè)小任務(wù)非常迅速和高效地處理,這一點(diǎn)我們已經(jīng)討論過了。
結(jié)論
我們已經(jīng)從理論到實(shí)踐討論過 Node.js 了,從它的目標(biāo)和野心,到其優(yōu)點(diǎn)和缺點(diǎn)。在 Node.js 的開發(fā)
中99%的問題是由誤用阻塞操作而造成的。
請(qǐng)記住:Node.js 從來(lái)不是用于解決大規(guī)模計(jì)算問題而創(chuàng)建的。它的出現(xiàn)是為了解決大規(guī)模I/O 的問題
,并且在這一點(diǎn)上做的非常好。
綜上,如果你項(xiàng)目需求中不包含CPU密集型操作,也不需要訪問任何阻塞的資源,那么你就可以利用的?
Node.js 的優(yōu)點(diǎn),盡情的享受快速、可擴(kuò)展的網(wǎng)絡(luò)應(yīng)用。
========
一個(gè)Java碼農(nóng)的Node之旅
本篇是一個(gè)Node新手做完實(shí)際項(xiàng)目后的心得總結(jié)。
摘要
如果BOSS要求你在短期內(nèi)快速實(shí)現(xiàn)一套聊天云服務(wù)平臺(tái),實(shí)現(xiàn)成本主要是:
要維護(hù)社交關(guān)系,一大波僵尸POJO正在襲來(lái)。
要存儲(chǔ)數(shù)據(jù)庫(kù),找個(gè)ORM工具。
長(zhǎng)連接吧方面是WebSocket標(biāo)準(zhǔn),亦或Netty、Mina系的框架。
連接斷了需要實(shí)現(xiàn)下重連機(jī)制吧?服務(wù)器端寫完了還有客戶端,也需要幫助指導(dǎo)下實(shí)現(xiàn),問題諸多。
我們的征途是偷懶
如果有現(xiàn)成的輪子偷懶的話,socket.io比較適合:
輕量級(jí)、擴(kuò)展便捷、API簡(jiǎn)單易用。
周邊完善,重連、路由、隔離、單播、廣播等都已實(shí)現(xiàn)。
豐富的客戶端支持,涵蓋了瀏覽器端、Android、iOS。
在仔細(xì)研讀了Flexi傳授如何說(shuō)服自己的老板采用Node.js,并成功說(shuō)服BOSS后,正式開始自己的Node之
旅。
工欲善其事必先利其器
開發(fā)環(huán)境
對(duì)于開發(fā)環(huán)境,無(wú)論你是使用編輯器/編輯器之神,或是sublime/atom/npp之類,亦或是WebStorm高富帥
有錢任性,都是很不錯(cuò)的選擇。
Supervisor可以幫你watch代碼變更,自動(dòng)重啟服務(wù),從而節(jié)省了手工重啟程序的時(shí)間。
關(guān)于調(diào)試
高富帥款:WebStorm
高逼格款:原始打斷點(diǎn)
屌絲款:node-inspector,可以在Chrome中直接調(diào)試,強(qiáng)烈推薦:
圖片描述
離不開的中間件
首先,勾勒出一個(gè)核心的聊天系統(tǒng)大致的雛形:
基本功能
集群實(shí)現(xiàn)
敏感詞過濾
好友
加好友,刪好友
好友之間聊天,發(fā)文字發(fā)圖片發(fā)音頻發(fā)視頻啥的
群組
創(chuàng)建,加入,退出群組
群組內(nèi)廣播聊天
聊天歷史記錄
擴(kuò)展與周邊
集群實(shí)現(xiàn)
敏感詞過濾
分析下大致需要的存儲(chǔ)層和中間件以及是否有相關(guān)的Node實(shí)現(xiàn):
MySQL:存儲(chǔ)一些重要的元數(shù)據(jù),主要是用戶關(guān)系類的,需要事務(wù)支持。(node-mysql)
ZooKeeper:用戶在線離線狀態(tài)存儲(chǔ)。(node-zookeeper-client)
Redis:使用緩存加速一些查詢,PubSub特性用于實(shí)現(xiàn)集群通訊。(ioredis)
HBase:典型的列式存儲(chǔ),用于實(shí)現(xiàn)一些非核心數(shù)據(jù)的快速存儲(chǔ)查詢。(hbase-rpc-client)
LevelDB:本地快速讀寫一些鍵值對(duì)。(LevelUP)
技術(shù)棧
對(duì)比
常年滋潤(rùn)在Java這片潤(rùn)土之上,先來(lái)做個(gè)比較,讓我們對(duì)陌生的技術(shù)棧有所了解。
圖片描述
ES6
ES6是個(gè)好東西, 我覺得比較好用的三點(diǎn):
const: 可以方便地對(duì)不可變的東西進(jìn)行聲明。
let: 只JavaScript初學(xué)者不用擔(dān)憂不知不覺把變量提升的問題。
lambda表達(dá)式: 神器。
核心實(shí)現(xiàn)
流程時(shí)序
仔細(xì)思考,勾勒出大致的時(shí)序圖:
圖片描述
系統(tǒng)架構(gòu):
設(shè)計(jì)下大致的架構(gòu):
圖片描述
步步為贏,各個(gè)擊破
狀態(tài)管理
典型的IM系統(tǒng)中必然存在用戶在線離線的狀態(tài)。每一個(gè)在線狀態(tài),對(duì)于服務(wù)器來(lái)說(shuō),等價(jià)于與客戶端存
在一個(gè)Socket連接。所以對(duì)于單機(jī)環(huán)境下,在內(nèi)存中維護(hù)用戶和Socket的關(guān)系即可,當(dāng)Socket連接和斷
開時(shí)分別做更新操作。當(dāng)切換至集群環(huán)境時(shí),情況變得稍微復(fù)雜,所以我們需要借助ZooKeeper來(lái)實(shí)現(xiàn)。
除了本機(jī)每個(gè)用戶與Socket關(guān)聯(lián)關(guān)系,另外以臨時(shí)節(jié)點(diǎn)的方式在ZooKeeper中進(jìn)行存儲(chǔ),目錄結(jié)構(gòu)為根節(jié)
點(diǎn)/命名空間/用戶標(biāo)識(shí)/Socket標(biāo)識(shí)(臨時(shí)節(jié)點(diǎn))。當(dāng)socket連接被建立的時(shí)候,創(chuàng)建對(duì)應(yīng)的臨時(shí)節(jié)點(diǎn),
socket斷開時(shí)移除臨時(shí)節(jié)點(diǎn)。當(dāng)服務(wù)器意外退出時(shí),除了socket連接全部斷開之外,在其ZooKeeper?
session上的所有對(duì)應(yīng)的臨時(shí)節(jié)點(diǎn)也會(huì)被銷毀。SocketIO的重連機(jī)制會(huì)嘗試重連至其他伺服器并重新建立
起對(duì)應(yīng)關(guān)系。
優(yōu)點(diǎn):
判斷一個(gè)用戶是否在線只需判斷用戶標(biāo)識(shí)節(jié)點(diǎn)的numChildren是否大于零即可。
獲取用戶所有已連接的Socket只需讀取用戶標(biāo)識(shí)下的所有孩子節(jié)點(diǎn)即可。
缺點(diǎn):
多了額外讀寫ZooKeeper的開銷。
用途:
實(shí)現(xiàn)集群的基礎(chǔ)
有了狀態(tài)判定才能實(shí)現(xiàn)離線消息推送
好友關(guān)系、群組關(guān)系
關(guān)系表原本存儲(chǔ)于HBase,但因?yàn)槿狈κ聞?wù)支持,實(shí)際效果不佳,經(jīng)常導(dǎo)致關(guān)系不一致。傳統(tǒng)關(guān)系型數(shù)據(jù)
庫(kù)在這一方面依舊強(qiáng)勢(shì)。這塊比較簡(jiǎn)單,即常見的關(guān)系模型表,在此略過。
點(diǎn)對(duì)點(diǎn)聊天實(shí)現(xiàn)
單機(jī)
A對(duì)B發(fā)送消息,除了基礎(chǔ)的權(quán)限判定,只需查詢內(nèi)存表中對(duì)應(yīng)B的所有socket,然后對(duì)其發(fā)射消息即可。
見下圖:
圖片描述
集群
由于B可能登錄在不同的服務(wù)器上,需要借助消息中間件(Redis Pub/Sub),發(fā)布消息,每個(gè)服務(wù)器訂閱
消息列表,如果存在消息接收者,則找到其注冊(cè)在本機(jī)的socket進(jìn)行發(fā)射消息。流程如下圖:
圖片描述
廣播聊天實(shí)現(xiàn)
廣播類似以上的點(diǎn)對(duì)點(diǎn)實(shí)現(xiàn),只是多了一步查詢成員表依次處理的步驟。此處略。
聊天歷史記錄的實(shí)現(xiàn)
考慮到只需要根據(jù)時(shí)間范圍做分頁(yè)查詢的簡(jiǎn)單需求,這里使用了HBase的寬表。點(diǎn)對(duì)點(diǎn)形式的聊天我們可
以對(duì)兩個(gè)用戶標(biāo)識(shí)進(jìn)行排序,并結(jié)合命名空間生成唯一的哈希值,作為行健,而每個(gè)CELL的值則是時(shí)間
戳,因?yàn)槲覀冃枰钇渥匀坏剐蚺帕?#xff0c;所以針對(duì)時(shí)間戳做了LONG。MAX-時(shí)間戳的處理。綜合起來(lái),大致
的存儲(chǔ)結(jié)構(gòu)如下:
圖片描述
敏感詞過濾
維護(hù)臟詞字典,對(duì)消息進(jìn)行字符串替換?為了實(shí)現(xiàn)正確辨認(rèn)“曹操在操場(chǎng)操美女”中的動(dòng)詞“操”,需
要實(shí)現(xiàn)中文分詞和詞性判斷,于是處理邏輯轉(zhuǎn)變成:
拉取最新的臟詞列表,轉(zhuǎn)換為簡(jiǎn)體中文并寫入LevelDB中。
使用nodejieba進(jìn)行中文分詞:曹操(n)/在(p)/操場(chǎng)(n)/操(v)/美女(n)
對(duì)分詞后的名詞和動(dòng)詞轉(zhuǎn)換為簡(jiǎn)體中文并查詢LevelDB,命中則替換。
返回替換后的字符串得到:曹操在操場(chǎng)*美女
打包部署
PM2
Node本身是單線程的,雖然Node本身提供Cluster模塊,但需要修改代碼。通過PM2這個(gè)工具可以簡(jiǎn)便地
讓其多進(jìn)程部署,充分利用多核CPU資源:
圖片描述
Docker
可以使用官方的node鏡像。但體積比較大,這里推薦基于alpine-node,體積比較小巧,例如:
FROM mhart/alpine-node:4
RUN apk add --no-cache make gcc g++ python
RUN apk add --no-cache imagemagick
WORKDIR /src
ADD . .
RUN npm install --registry=http://registry.npm.taobao.org/
EXPOSE 3000
CMD ["npm","start"]
C1000K測(cè)試
著名的單機(jī)100萬(wàn)連接,由于項(xiàng)目是第一個(gè)版本,限于各方面原因我們暫時(shí)沒有完成這個(gè)測(cè)試。但在這里
簡(jiǎn)短介紹所需的一些配置,以備后續(xù)使用:
服務(wù)器端
修改tcp連接的最小內(nèi)存為4k, 編輯/etc/sysctl.conf
net.ipv4.tcp_wmem = 4096 87380 4161536
net.ipv4.tcp_rmem = 4096 87380 4161536
net.ipv4.tcp_mem = 786432 2097152 3145728
修改系統(tǒng)最大文件描述符, 編輯/etc/sysctl.conf
fs.file-max = 1000000
修改進(jìn)程最大文件描述符, 編輯/etc/security/limits.conf
* ? ? ? ? hard ? ?nofile ? ? ?1000000
* ? ? ? ? soft ? ?nofile ? ? ?1000000
root ? ? ?hard ? ?nofile ? ? ?1000000
root ? ? ?soft ? ?nofile ? ? ?1000000
重載下配置(sysctl -p)或者重啟,檢查下當(dāng)前的設(shè)置 cat /proc/sys/fs/file-nr
*客戶端
因?yàn)槊總€(gè)IP最多可以創(chuàng)建6萬(wàn)多個(gè)連接,不可能找很多服務(wù)器進(jìn)行測(cè)試。所以客戶端除了上述修改,還需
要?jiǎng)?chuàng)建多個(gè)虛擬IP,這樣每個(gè)IP可以提供大約6萬(wàn)的連接,如:
?ifconfig eth0:0 192.168.77.10 netmask 255.255.255.0 up
?ifconfig eth0:1 192.168.77.11 netmask 255.255.255.0 up
?ifconfig eth0:2 192.168.77.12 netmask 255.255.255.0 up
?ifconfig eth0:3 192.168.77.13 netmask 255.255.255.0 up
?ifconfig eth0:4 192.168.77.14 netmask 255.255.255.0 up
?ifconfig eth0:5 192.168.77.15 netmask 255.255.255.0 up
?ifconfig eth0:6 192.168.77.16 netmask 255.255.255.0 up
?ifconfig eth0:7 192.168.77.17 netmask 255.255.255.0 up
?ifconfig eth0:8 192.168.77.18 netmask 255.255.255.0 up
?ifconfig eth0:9 192.168.77.19 netmask 255.255.255.0 up
?ifconfig eth0:10 192.168.77.20 netmask 255.255.255.0 up
?ifconfig eth0:11 192.168.77.21 netmask 255.255.255.0 up
?ifconfig eth0:12 192.168.77.22 netmask 255.255.255.0 up
?ifconfig eth0:13 192.168.77.23 netmask 255.255.255.0 up
?ifconfig eth0:14 192.168.77.24 netmask 255.255.255.0 up
?ifconfig eth0:15 192.168.77.25 netmask 255.255.255.0 up
?ifconfig eth0:16 192.168.77.26 netmask 255.255.255.0 up
?ifconfig eth0:17 192.168.77.27 netmask 255.255.255.0 up
?ifconfig eth0:18 192.168.77.28 netmask 255.255.255.0 up
修改本地端口范圍,編輯/etc/sysctl.conf
? ? net.ipv4.ip_local_port_range = 1024 65535
重載配置或重啟開始測(cè)試
總結(jié)
存在即合理,不要卷入無(wú)謂的語(yǔ)言之爭(zhēng),本猿覺得干這行的最重要莫過于學(xué)習(xí)能力。?
寫代碼之前先理清楚思路和結(jié)構(gòu),不打沒有準(zhǔn)備的仗。
良好的代碼規(guī)范,遵循KISS原則。
========
相關(guān)鏈接
http://www.yiibai.com/nodejs/
http://www.runoob.com/nodejs/nodejs-tutorial.html
http://nodejs.cn/
http://blog.jobbole.com/53736/
http://www.csdn.net/tag/Node/news
總結(jié)
以上是生活随笔為你收集整理的node.js学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eclipse开发Spring MVC入
- 下一篇: Mysql非安装版的安装使用相关问题