鍍金池/ 教程/ HTML/ 番外篇之——使用 generic pool
第9章 增加標(biāo)簽和標(biāo)簽頁(yè)面
番外篇之——使用 Mongoose
番外篇之——使用 Async
第4章 實(shí)現(xiàn)用戶(hù)頁(yè)面和文章頁(yè)面
第12章 增加友情鏈接
第14章 增加頭像
第7章 實(shí)現(xiàn)分頁(yè)功能
第5章 增加編輯與刪除功能
第11章 增加文章檢索功能
第3章 增加文件上傳功能
番外篇之——部署到 Heroku
第2章 使用 Markdown
第13章 增加404頁(yè)面
第16章 增加日志功能
第1章 一個(gè)簡(jiǎn)單的博客
番外篇之——使用 Handlebars
第10章 增加pv統(tǒng)計(jì)和留言統(tǒng)計(jì)
番外篇之——使用 Passport
第15章 增加轉(zhuǎn)載功能和轉(zhuǎn)載統(tǒng)計(jì)
第8章 增加存檔頁(yè)面
番外篇之——使用 generic pool
番外篇之——使用 _id 查詢(xún)
番外篇之——使用 Disqus
番外篇之——使用 KindEditor
第6章 實(shí)現(xiàn)留言功能

番外篇之——使用 generic pool

目前為止,我們都是這樣處理請(qǐng)求的,比如:當(dāng)用戶(hù)訪問(wèn)某個(gè)文章頁(yè)的時(shí)候,系統(tǒng)會(huì)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接,通過(guò)該連接到數(shù)據(jù)庫(kù)中查找并返回該文章的數(shù)據(jù),然后關(guān)閉該連接。但是當(dāng)我們的博客訪問(wèn)量巨大的時(shí)候,頻繁的創(chuàng)建和銷(xiāo)毀連接會(huì)產(chǎn)生非常大的系統(tǒng)開(kāi)銷(xiāo)。這個(gè)時(shí)候,我們就需要引入數(shù)據(jù)庫(kù)連接池了。

什么是連接池(connection pool)呢?維基百科中是這樣定義的:

connection pool is a cache of database connections maintained so that the connections can be reused when future requests to the database are required.

說(shuō)白了就是,我們一開(kāi)始就創(chuàng)建一沓數(shù)據(jù)庫(kù)連接,并保持長(zhǎng)連不斷開(kāi)。當(dāng)我們需要訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候,就去那一沓連接(俗稱(chēng)連接池)中拿來(lái)一個(gè)用,用完(對(duì)數(shù)據(jù)庫(kù)增刪改查完)后再把這條連接釋放到連接池中(依然不斷開(kāi))。這樣我們只在一開(kāi)始創(chuàng)建一沓數(shù)據(jù)庫(kù)連接時(shí)會(huì)有一些開(kāi)銷(xiāo),而這種開(kāi)銷(xiāo)總比頻繁的創(chuàng)建和銷(xiāo)毀連接小得多。

在 Node.js 中,我們可以使用 generic-pool 這個(gè)模塊幫助我們創(chuàng)建和管理數(shù)據(jù)庫(kù)連接池。

首先,在 package.json 中添加對(duì) generic-pool 的依賴(lài):

"generic-pool": "*"

并 npm install 安裝 generic-pool 模塊。

打開(kāi) db.js ,將:

module.exports = new Db(settings.db, new Server(settings.host, settings.port), {safe: true});

修改為:

module.exports = function() {
  return new Db(settings.db, new Server(settings.host, settings.port), {safe: true, poolSize: 1});
}

這里我們導(dǎo)出一個(gè)函數(shù),每次調(diào)用該函數(shù)則創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接。

打開(kāi) post.js ,將:

var mongodb = require('./db'),
    markdown = require('markdown').markdown;

修改為:

var Db = require('./db');
var markdown = require('markdown').markdown;
var poolModule = require('generic-pool');
var pool = poolModule.Pool({
  name     : 'mongoPool',
  create   : function(callback) {
    var mongodb = Db();
    mongodb.open(function (err, db) {
      callback(err, db);
    })
  },
  destroy  : function(mongodb) {
    mongodb.close();
  },
  max      : 100,
  min      : 5,
  idleTimeoutMillis : 30000,
  log      : true
});

以上就創(chuàng)建了一個(gè) mongodb 連接池,其中 name 指明該連接池的名字,create 指明創(chuàng)建一條數(shù)據(jù)庫(kù)連接的方法,并返回創(chuàng)建的連接,destroy 指明如何銷(xiāo)毀連接,max 指明連接池中最大連接數(shù),min 指明連接池中最小連接數(shù),idleTimeoutMillis 指明不活躍連接銷(xiāo)毀的毫秒數(shù),這里為 30000 即當(dāng)一條連接 30 秒處于不活躍狀態(tài)(即沒(méi)有被使用過(guò))時(shí)則銷(xiāo)毀該連接。log 指明是否打印連接池日志,這里我們選擇打印。

如何使用連接池呢?很簡(jiǎn)單。只需將所有:

mongodb.open(function (err, db) {
  ...
  mongodb.close();
});

修改為:

pool.acquire(function (err, mongodb) {
  ...
  pool.release(mongodb);
});

這里我們使用 pool.acquire 去連接池中獲取一條可用連接,使用完畢后通過(guò) pool.release 釋放該連接,而不是 close 掉。

讀者可自行完成剩余的修改工作。