如何提升nodejs程序的穩定性,健壯性

  在網上看到一些帖子,吐糟,質疑nodejs 程序的穩定性,爲何呢?其一,可能這個和javascript有關吧,node是拿javascript去實現的,而javascript又被稱爲是「世界上誤解最深的語言」,咱們能夠去看看nodejs 創始人的說法,能夠去看看知乎的這篇文章,爲何node 用javascript去實現,其二,nodejs 畢竟還年輕,並且官網在部分模塊也標註了此模塊的目前的狀態。javascript

  這2天我抽了點時間思考了下這個問題,我以爲咱們程序首先功能應該是獨立的,就是一個功能出異常了,不該該去影響另一個正常的功能,不該該將整個程序都崩潰掉,其次,即便是程序崩潰了,咱們也應該有一個讓程序自動啓動,另外,應該去記錄日誌,方便咱們跟蹤問題。我以爲主要能夠從如下方面提升nodejs 穩定性:html

  1)保持良好的代碼結構:java

    咱們知道node是單線程,非阻塞io,默認就是異步,經過回調的方式處理後面的流程,若是嵌套的層次太多了,勢必會引發代碼邏輯結構的混亂,也不利於維護和升級,能夠採用async這個異步流程控制模塊,來理清咱們的代碼邏輯。node

  2)使用 process.on('uncaughtException', function(err){...}); 來處理未被捕捉的錯誤。git

  3)使用try~catch 來捕獲異常:github

     這個只能解決一部分問題,不是萬能的,在上面說到由於node是單線程,非阻塞io,默認就是異步,經過回調的方式處理後面的流程,try~catch 是不能捕獲的callback 裏面的error的錯誤的,怎麼捕獲到callback裏面的錯誤呢 ? 能夠採用domain模塊api

  4)使用domain模塊來處理程序的異常服務器

     先看看對domain的解釋:domain是 EventEmitter類的一個子類。監聽它的error事件來處理它捕捉到的錯誤。 它提供了一種方式,即以一個單一的組的形式來處理多個不一樣的IO操做。若是任何一個註冊到domain的事件觸發器或回調觸發了一個‘error’事件,或者拋出一個錯誤,那麼domain對象將會被通知到。而不是直接讓這個錯誤的上下文從`process.on('uncaughtException')'處理程序中丟失掉,也不會導致程序由於這個錯誤伴隨着錯誤碼當即退出。app

  如何使用domain 模塊呢?看一個例子:dom

serverDomain.run(function() {
  // 服務器在serverDomain的做用域內被建立
  http.createServer(function(req, res) {
    // req和res一樣在serverDomain的做用域內被建立
    // 可是,咱們想對於每個請求使用一個不同的域。
    // 因此咱們首先建立一個域,而後將req和res添加到這個域上。
    var reqd = domain.create();
    reqd.add(req);
    reqd.add(res);
    reqd.on('error', function(er) {
      console.error('Error', er, req.url);
      try {
        res.writeHead(500);
        res.end('Error occurred, sorry.');
      } catch (er) {
        console.error('Error sending 500', er, req.url);
      }
    });
  }).listen(1337);    
});
```

說明:首先建立一個域(domain.create()),而後將須要監控的分發器添加到該域上,最後給域綁定一個錯誤事件,這樣就能夠監控了。

再看一個例子:

var d = domain.create();
d.on('error', function(er) {
  console.error('Caught error!', er);
});
d.run(function() {
  process.nextTick(function() {
    setTimeout(function() { // 模擬幾個不一樣的異步的東西
      fs.open('non-existent file', 'r', function(er, fd) {
        if (er) throw er;
        // 繼續。。。
      });
    }, 100);
  });
});

說明:首先建立一個域,給域綁定一個錯誤事件,而後在域的上下文提供能夠運行的函數

若是對於回調呢?能夠這麼使用

var d = domain.create();

function readSomeFile(filename, cb) {
  fs.readFile(filename, 'utf8', d.bind(function(er, data) {
    // if this throws, it will also be passed to the domain
    return cb(er, data ? JSON.parse(data) : null);
  }));
}

d.on('error', function(er) {
  // an error occurred somewhere.
  // if we throw it now, it will crash the program
  // with the normal line number and stack message.
});

固然也能夠這麼使用

var d = domain.create();

function readSomeFile(filename, cb) {
  fs.readFile(filename, 'utf8', d.intercept(function(data) {
    return cb(null, JSON.parse(data));
  }));
}

d.on('error', function(er) {
  // an error occurred somewhere.
  // if we throw it now, it will crash the program
  // with the normal line number and stack message
});

這個函數與domain.bind(callback)幾乎如出一轍。可是,除了捕捉被拋出的錯誤外,它還會攔截做爲第一參數被傳遞到這個函數的Error對象。

  5)使用log4js 模塊記錄日誌

  log4js 是一個很是強大的日誌管理工具,在能夠看看github這個項目: https://github.com/nomiddlename/log4js-node

  6)使用forever 模塊來管理nodejs

  forever 是服務端管理nodejs 的一個模塊,一個命令行工具,可以啓動,中止app 應用。forever徹底是基於命令行操做,在forever進程管理之下,建立node的子進程,經過monitor監控node子進程的運行狀況,一旦文件更新,或者進程掛掉,forever會自動重啓node服務器,確保應用正常運行。很是的好用.

能夠關注下這個項目:https://github.com/nodejitsu/forever

可是forever 也不是萬能的,也由下面這些問題:

  • 有限的監控和日誌功能
  • 進程管理配置的支持差
  • 不支持集羣
  • 代碼庫老化(意味着在升級node.js時頻繁的失敗)

附本文測試代碼:https://github.com/yupeng528/node-error  

相關文章
相關標籤/搜索