Node.js 服務連線 MongoDB 處理最佳實踐

逆葵發表於2018-10-24

關於如何處理 node.js 服務連線 MongoDB,我查閱了大量中英文資料,發現並沒有太適合我所期望的能力的方案,因此經過一番官方文件的研究,總結了以下的連線 MongoDB 的方法(使用目前 Node.js 平臺最常用的 MongoDB ODM mongoose),斗膽稱之為『最佳實踐』,希望能夠拋磚引玉,得到大家更專業的解答。 話不多說,先上程式碼:

const mongoose = require('mongoose')
const config = require('./config')


if (process.env.NODE_ENV === 'development') {
  mongoose.set('debug', true)    /* A */
}

mongoose.set('bufferCommands', false)  /* B */

function connectMongoDB(address) {
  try {
    mongoose.connect(address, { 
      useNewUrlParser: true,
      bufferMaxEntries: 0   /* B */
      autoReconnect: true   /* C, default is true, you can ignore it */
      poolSize: 5           /* D, default is 5, you can ignore it */
    })
    
    const db = mongoose.connection
    db.on('error', (error) => {
      console.log(`MongoDB connecting failed: ${error}`)
    })
    db.once('open', () => {
      console.log('MongoDB connecting succeeded')
    })
    return db
  } catch (error) {
    console.log(`MongoDB connecting failed: ${error}`)
  }
}

const mongoInstance = connectMongoDB(config.database.mongo)
module.exports = {
    mongoInstance
}
複製程式碼

這套連線方法能夠滿足以下需求,當然,這也是從我的服務需要滿足的需求中總結而來的:

  1. 開發環境下能夠列印詳細的資料庫操作資訊
  2. 與資料庫斷開連線後,所有涉及到資料庫讀寫操作的命令均會立即返回錯誤,而不會等待重連進而造成介面超時
  3. 服務啟動併成功與資料庫建立連線後,如果資料庫出現問題造成連線中斷,服務會自動嘗試重連直到連線成功
  4. 無需手動處理連線數

我們逐條來看每個需求對應的配置:

  1. 見註釋 A,在開發環境中設定 'debug' 為 true,資料庫將會把集合方法和引數列印到控制檯。
  2. 見兩處註釋 B,這裡貼一段 mongoose 文件中對 bufferMaxEntries 的解釋:

bufferMaxEntries - The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set bufferCommands to false on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.

核心意思就是將 bufferMaxEntries 設為 0 同時將 bufferCommands 設為 false,可以讓驅動在未連線到資料庫的時候,操作立即返回失敗,而不是一直在等待重連。個人認為,這種方式相比一直等待資料庫重連直到響應超時體驗要更佳一點。

  1. 見註釋 C,這實際上是 mongoose 的預設設定,其連線資料庫時的 config 引數 autoReconnect 預設為 true,其含義見文件:

autoReconnect - The underlying MongoDB driver will automatically try to reconnect when it loses connection to MongoDB. Unless you are an extremely advanced user that wants to manage their own connection pool, do not set this option to false.

如果非高階使用者,就不要去改變這個引數了。

  1. 見註釋 D。對於 MongoDB 連線池的問題,建議是不要去手動處理。mongoose 自己會維護一個預設最大數量為 5 的連線池,只有當你發現有一些慢查詢可能阻塞快查詢時才應該考慮增大 poolSize。當然,這個數字不能設定得過大,MongoDB 預設是一個連線啟動一個執行緒來服務,連線太多執行緒數切換系統開銷會很大。

當然,以上這套『最佳實踐』還存在一個不足:如果服務初次啟動後未能成功連線資料庫(比如資料庫此時處於當機狀態),則服務不會嘗試重連資料庫。解決方法也不是沒有,就是比較雞肋:在 mongoose 連線的 'error' 事件監聽回撥函式中嘗試重連。但是需要設定最大重試次數,否則會發生記憶體洩露。比較雞肋的原因是,如果首次連線沒有成功,短時間內嘗試重連幾次貌似也無濟於事。因此,使用這套連線方式務必要注意資料庫保持可連線狀態。或者讀者們如果有更好的解決方案,也希望能不吝賜教。

完。

本文首發於我的部落格(點此檢視),歡迎關注。

相關文章