1. 程式人生 > >生產級Nodejs開發實踐-使用連接池

生產級Nodejs開發實踐-使用連接池

article data cache span 打開 lin master etime 默認

引言

做後端開發免不了要和一些 存儲服務器, 消息服務器 等等 打交道。

起因 (傳統模式, 讀取數據庫)

大家都知道和這些使用 tcp連接 的服務傳遞數據的都必須要打開 一個 連接-connection

例如我們打開一個數據庫並執行一段 sql, 通常都是

  1. connection = open "mysql://127.0.0.1:3306/db" (打開數據庫,並取得持有連接的句柄)
  2. data = connection.exec "select * from table1" (執行 sql 並獲取數據)
  3. connection.close() 顯式的關閉連接

這個方式看上去似乎沒有什麽不對的。

但是對於並發量稍大一些的站點來說。一個單元批次的操作就需要打開並關閉一次連接。。。
顯然是不能接受的

為這樣做不能接受呢?

建立一個tcp連接需要三次握手。而且還需要為對象分配系統資源和內存空間。所以創建一個tcp連接可以說是昂貴的。

回到剛才的話題。這樣平凡的開啟關閉連接不僅對增加客戶端io的壓力,最重要的是大大增加了 tcp 服務器的壓力(mysql, redis)。

那我們再嘗試另外一種方式,那就是不關閉連接,一直使用這個連接呢。答案是: 可以。這種方式 被叫做 長連接

那這樣的話,也有一個問題。因為一段時間內一個連接只能做一件事情。那麽在並發的情況下這顯然會阻塞整個系統。

那我們能不能嘗試創建多個連接,然後當調用的時候,將沒有被使用的連接拿出來使用,當使用完畢之後,將連接放回去,以供其他調用者使用

的方式的呢?

連接大管家(連接池)

答案是有的:那就是我們要說的連接池。當然一個健全的連接池並不僅僅完成以上我所說的功能。

  • 連接預熱 (啟動時自動打開n個連接以供使用)
  • 使用 例如 輪轉法 均勻分發 連接請求
  • 當池中的連接即將耗盡得時候動態產生新的連接
  • 當池中的連接一段時間沒有被調用的時候,自動釋放連接
  • 自動丟棄 已經壞掉的 連接
  • 系統關閉的時自動釋放所有連接
    ........

以上都屬於連接池的功能。連接池可謂是我們管理連接的管家

Node.js 中的 連接池

說到這裏好像還是沒有說到要點。在Node中我們應該怎麽呢?

我們可以使用 node-pool 這個模塊 GitHub

1. 安裝 

    npm install generic-pool
2. 創建一個連接池       
    // 創建一個 mysql 連接池
    var poolModule = require(‘generic-pool‘);
    var pool = poolModule.Pool({
        name     : ‘mysql‘,
        //將建 一個 連接的 handler
        create   : function(callback) {
                var Client = require(‘mysql‘).Client;
                var c = new Client();
                c.user     = ‘scott‘;
                c.password = ‘tiger‘;
                c.database = ‘mydb‘;
                c.connect();
                callback(null, c);
        },
        // 釋放一個連接的 handler
        destroy  : function(client) { client.end(); },
        // 連接池中最大連接數量
        max      : 10,
        // 連接池中最少連接數量
        min      : 2, 
        // 如果一個線程3秒鐘內沒有被使用過的話。那麽就釋放
        idleTimeoutMillis : 30000,
        // 如果 設置為 true 的話,就是使用 console.log 打印入職,當然你可以傳遞一個 function 最為作為日誌記錄handler
        log : true 
    });
3. 從連接池中獲得鏈接並使用
    // 默認無任務優先級, 但是與高優先級一樣,在競爭隊列的前列
    pool.acquire(function(err, client) {
       pool.release(client);
    });

    // 高優先級獲得鏈接, 在競爭隊列的前列
    pool.acquire(function(err, client) {
       pool.release(client);
    }, 0);

     // 中等優先級獲得鏈接
     pool.acquire(function(err, client) {
         pool.release(client);
     }, 1);

     // pool.acquire(handler, priority) 方法接受連個參數 
     // handler: 獲取連接的回掉函數
     // priority: 獲取到鏈接的競爭優先級
     // pool.release(client) 方法會將鏈接放回到連接池當中,當獲得的鏈接沒有release的話。將會導致該鏈接被一直占用

更多相關的配置 我就不一一展開討論了。大家可以去 github 上查看項目的 README.md

【生產級別Nodejs開發實踐-強壯的node進程容器PM2】- 敬請期待

註:
存儲服務器: (數據庫 mysql ..., 緩存 memcached, redis ...)
消息服務器: (RabbitMQ,ActiveMQ ...)

  • 2014年12月18日發布

生產級Nodejs開發實踐-使用連接池