Cloud9 Web Code Editor

Cloud9:滿足了我前陣子的想像,在網頁上編輯且擴充性與整合性頗高的程式編輯器,整合了HTML5的多種技術,由 ajax.org 所推出,他們有自己開發的 ajax ui framework,幾乎都整合再這個專案上了,成果蠻令人感到驚艷。他在伺服器端採用 nodejs 運作 websocket 與 webserver 來達到檔案同步更新監控等功能,再用完整的 ui framework 打造完整的環境,並整合 nodejs 開發 debug 環境…支援多種程式語言與 highlight 樣式

前陣子在做這件事的有 Mozilla 的 Bespin https://bespin.mozillalabs.com/ ,但他專注在編輯器上面,沒有像 cloud9 提供完善的週邊與擴充性,且 cloud9 自行開發的編輯器 ace https://github.com/ajaxorg/ace,呈現的效果也是頗佳,甚至比我當初用的bespin 更貼近桌面的版本,但是在中文的支援上一樣有一些問題,且 ace 竟然只採用 html 就能得到這種效果,有點想不到,比 bespin canvas 的操作上更佳一些。

在自行從 github 抓下來的 cloud9 上建構有遇到一些問題,在此紀錄一下,我用的環境是 CentOS 5.4 64bit,使用 bin/cloud9.sh 編譯,他會依照 .gitmodule 內的內容去將子模組抓下來,但似乎是我環境 https 的設定有問題,所以完全都抓不下來,我就將 repos 網址全改為 git://… ,就可以抓了,順利的話 support 內的子模組資料夾會被填滿,如果不行就自行手動下指令吧。

接著 jsdav 內也有子模組要做一次更新的動作,最後執行後會發生但是會遇到 glibc 版本的錯誤訊息,,應是 o3 支援的版本與環境有差異。

git submodule update --init --recursive

接著就按照他官網說明文件上的編譯,可能會需要再額外安裝 libxml2 與 libxml2-devel 用 yum 裝就編譯 ok 囉。

$ git clone http://github.com/ajaxorg/o3
$ cd o3
$ ./tools/node_modules_build
$ cp build/default/o3.node cloud9dir/support/jsdav/support/node-o3-xml/lib/o3-xml/

在搭配 FUSE + sshfs 可以掛載遠端資料夾在本地端,這樣可以實現類似 ftp 編輯的效果,安裝完以後出現一點問題,sshfs not fount fuse shared library

修改 ld.so.conf 加入 /usr/local/lib 以後執行 ldconfig 重載以後就ok囉

sshfs [email protected]:/path  mountdir

http://fuse.sourceforge.net/sshfs.html

http://fuse.sourceforge.net/

最近 cloud9 推出了整合 github 帳號與 repos 的開發執行環境, cloud9ide ,可以用 github 帳號申請,然後登入後他會讓你選擇你要編輯的專案,

就會進去個人專案的環境,也可線上下指令 commit 與 push 你的專案,甚至可以運行一個 nodejs http 的 process ,他似乎微調了 nodejs 的內部,整合了一個類似虛擬伺服器的東西,

讓你在指定的 port 下運行時也可以帶有一個網域,例如 http://ace.mlwmlw.cloud9ide.com : 網域格式是 專案:帳號.cloud9ide.com ,只要指定的 port 是 .listen(process.env.C9_PORT, “0.0.0.0”);

2011 1 25 更新

http://www.theregister.co.uk/2011/01/20/mozilla_skywriter_ace_ajax/

這幾天的新聞,skywrite(bespin)打算要跟 ajax.org 專案合作 要打造 coding in the cloud 的環境了~

http://mozillalabs.com/skywriter/2011/01/18/mozilla-skywriter-has-been-merged-into-ace/

要將 skywrite 合併到 ace(ajax.org code editor)…蠻令人振奮的消息…他們做的都是我曾經想過的事…但他們都做的更好而且要合作了~又是 open source 的專案,

希望以後能夠有很好的 web ide 可以使用~

nodejs 多核心web框架

這篇文章主要在講解因為 nodejs 採用單一執行緒的 事件驅動模型,所以在多核心的主機上要利用多顆 cpu 要怎麼處理,大概就是用多個行程來建數個 Web Server,然後再寫一個 Load Balance 來協調各 Server 間的工作。
我稍稍修改用語..另外有一篇 http://blog.kadirpekel.com/2010/07/28/meryl-a-thin-web-layer-for-nodejs/ 講 meryl 這個web 框架 還有講到 npm http://github.com/isaacs/npm 是 a little package manager for node

 

譯自:http://developer.yahoo.net/blog/archives/2010/07/multicore_http_server_with_nodejs.html(稍有修改), 轉載請指明原文鏈接:http://www.grati.org/?p=307

簡單的說,NodeJS是一個使用了Google高效能 V8引擎 的服務器端JavaScript實做。它提供了一個(幾乎)完全非阻塞I/O,與JavaScript提供的閉包和匿名函數結合,使之成為寫撰寫高流量網路服務程序的優秀平台。在我們內部,雅虎郵件隊正調研能否使用NodeJS開發一些我們即將推出的新服務。我們認為分享我們的勞動成果是一件十分有意義的事情。

目錄

在多處理器系統上使用NodeJS的情況

NodeJS中並不是完美無缺的。雖然單一行程的性能表現相當不錯,但一個CPU最終還是不夠用(由於JS引擎自身的運行原理,NodeJS使用單行程執行JS程式,詳見「JS和多執行序」)。Node本身並沒有擴展能力來充分利用多CPU系統的計算能力。實際上當前版本的NodeJS程序只能在一個上CPU執行,在2.5GHz的英特爾至強處理器下運行HTTP代理服務的性能大約為2100 reqs/s。

雖然Node相對穩定,但它仍然會偶爾崩潰。如果你實用一個單獨的NodeJS 行程作為服務,崩潰會對可用性造成不良影響。例如段暫存器錯誤 記憶體溢位等錯誤在用C++編寫的程序上相當普遍。如果有多個行程同時處理請求,當一個行程出錯退出,傳入的請求可以被導向給其他行程

充分利用多核心處理器的優勢

有如下幾種方法可以使NodeJS利用多處理器,每個方法都有自己的優缺點。

使用軟體負載均衡

直到node-v0.1.98 ,充分利用多處理器的最佳做法是為每個處理器單獨啟動一個NodeJS進程,每個行程都運行HTTP服務並綁定到不同的端口。這樣需要一個負載平衡軟體,將客戶端請求轉發到各行程,這個軟體知道每個服務行程

的port。這樣處理效能也不錯,但配置管理多行程比較複雜,因此不是最佳方案。

當然,這種架構也有好處,它允許負載平衡軟體按照指定的策略將請求路由到不同行程上。(例如,透過IP,透過cookie等)。

使用作業系統核心做負載平衡

node-v0.1.98中 ,雅虎貢獻了一個用於傳遞和重用文件描述符的核心patch,允許如Connectmulti-node等HTTP框架使用多個行程同時提供HTTP服務,而且不需要修改原有的程式碼和配置。

概括的講,這些框架使用的方法是建立一個行程監聽埠(比如說監聽埠80)。然而,這個行程不是接受Socket連接,而是使用net.Stream.write()將其傳遞給了其他子行程(其內部是使用sendmsg(2)發送,並使用recvmsg來獲取文件表描述符)。每個子行程排隊將收到的文件描述符插入自己的事件迭代中並在空閒時處理客戶端的連接。OS核心本身負責行程間的負載平衡。

重要的是,這實際上是一個高效但沒有策略的L4負載平衡器,每個客戶端的請求可能被任意一個行程處理。任何處理請求所需的應用程序的狀態,都不能像單行程時那樣簡單的保存在一個NodeJS實例當中。

使用NodeJS轉發請求

某些情況下,你可能可能無法使用或者不想使用上述兩種方法。例如,負載均衡程序無法按照應用程序所需的路由規則轉發請求(如,有複雜應用邏輯的路由規則或者需要SELinux連接信息的路由規則)。在這種情況下,可以使用單個進程接受連接,檢查並傳遞給其他進程處理。

下面的例子需要node-v0.1.100或更高版本以及node-webworker 。node-webworker是新興的HTML5 Web Workers標準的NodeJS實現,這個標準允許並行執行JavaScript代碼。您可以使用npm安裝node-webworker,命令如下 npm install webworker@stable。

詳細介紹Web Workers的原理超出了這篇文章的範圍,你可以認為Web Worker是一個獨立的執行上下文(類似行程),它可以由JavaScript程式碼生成並來回傳遞數據。node-webworker允許使用如下消息傳遞機制傳遞文件描述符:

首先,主行程的原始碼master.js:

var net = require('net');
var path = require('path');
var sys = require('sys');
var Worker = require('webworker/webworker').Worker;
var NUM_WORKERS = 5;
var workers = [];
var numReqs = 0;
for (var i = 0; i < NUM_WORKERS; i++) {
  workers[i] = new Worker(path.join(__dirname, 'worker.js'));
}
net.createServer(function(s) {
  s.pause();
  var hv = 0;
  s.remoteAddress.split('.').forEach(function(v) {
    hv += parseInt(v);
  });
  var wid = hv % NUM_WORKERS;
  sys.debug('Request from ' + s.remoteAddress + ' going to worker ' + wid);
  workers[wid].postMessage(++numReqs, s.fd);
}).listen(80);

主行程將執行如下操作:

  • 主行程將建立net.Server實例並在80埠上偵聽連接請求。
  • 當請求到來時,主行程
    • 根據請求端的IP地址決定將請求發送至哪一個wroker。
    • 調用請求流對象的net.Stream.pause()方法。這可以防止主行程從讀取套接字中讀取數據 — wroker行程應該看到遠程端發送的所有數據。
    • 使用postMessage()方法將(遞增後的)全局請求計數器和剛剛收到
      套接字描述符發送到指定的worker

然後,worker進程的源代碼worker.js:

var http = require('http');
var net = require('net');
var sys = require('sys');
process.setuid('nobody');
var srv = http.createServer(function(req, resp) {
  resp.writeHead(200, {'Content-Type' : 'text/plain'});
  resp.write(
    'process=' + process.pid +
    '; reqno=' + req.connection.reqNo + '\n'
  );
  resp.end();
});
onmessage = function(msg) {
  var s = new net.Stream(msg.fd);
  s.type = srv.type;
  s.server = srv;
  s.resume();
  s.reqNo = msg.data;
  srv.emit('connection', s);
};

worker執行如下操作:

  • 將自己的權限降為nobody用戶。
  • 創建一個HTTP服務器實例但並不調用任何listen()方法。我們將通過主進程收到的描述符來傳遞請求。
  • 等待從主進程接收套接字描述符和相關信息
  • 將從主進程收到的請求計數保存進流對象(stream.object)中,代碼有些亂,但讓我們可以使用HTTP相關的類來處理這些數據。
  • 將net.Stream實例和收到的TCP鏈接接合,然後通過手動觸發事件將其融入HTTP請求的處理流程中。
  • 現在,我們如上建立的請求處理程序可以正常運行了: HTTP服務實例完全擁有連接並將像平常一樣解理客戶端的請求。注意一個小技巧,請求處理程序訪問流對象的reqNo屬性,並根據主進程中的計數變量(既用於記錄請求數的全局變量numReqs)將其設置為實際的請求數。

最後,一定要使用超級用戶執行master.js,因為我們希望程序監聽特權端口(80)。然後使用curl 發出一些請求,並看看是那個進程處理這些請求。

% sudo node ./master.js % curl 'http://localhost:80'
process=13049; reqno=2

當然,前面例子用到的基於IP的哈希算法是玩具級的,任何一個合格的HTTP負載均衡器能可以實現。在現實中,你可能想根據客戶端的請求,將連接分派到運行在正確的SELinux上下文中的worker。(參見,node-selinux)根據HTTP請求本身的的信息(如:path,vhost)作出路由決策稍微複雜些,且使用類似的技術也可行。

結論

最 後,我希望本文能夠說明當前NodeJS利用多處理器的情況:一些現有的HTTP框架可以給各種NodeJS應用提供多處理器支持;node- webworkers為管理NodeJS中的並行機制提供了一個好方法(基於chlid_proess);怎樣實用NodeJS自身實現L7 HTTP路由器。

示例代碼